diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 0fffedcb6ae88..533b81013a264 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -57,22 +57,6 @@ jobs: # Also install zh_CN (its encoding is gb2312) but do not activate it. # It will be temporarily activated during tests with locale.setlocale extra_loc: "zh_CN" - - name: "Copy-on-Write 3.9" - env_file: actions-39.yaml - pattern: "not slow and not network and not single_cpu" - pandas_copy_on_write: "1" - - name: "Copy-on-Write 3.10" - env_file: actions-310.yaml - pattern: "not slow and not network and not single_cpu" - pandas_copy_on_write: "1" - - name: "Copy-on-Write 3.11" - env_file: actions-311.yaml - pattern: "not slow and not network and not single_cpu" - pandas_copy_on_write: "1" - - name: "Copy-on-Write 3.12" - env_file: actions-312.yaml - pattern: "not slow and not network and not single_cpu" - pandas_copy_on_write: "1" - name: "Pypy" env_file: actions-pypy-39.yaml pattern: "not slow and not network and not single_cpu" @@ -101,7 +85,6 @@ jobs: PATTERN: ${{ matrix.pattern }} LANG: ${{ matrix.lang || 'C.UTF-8' }} LC_ALL: ${{ matrix.lc_all || '' }} - PANDAS_COPY_ON_WRITE: ${{ matrix.pandas_copy_on_write || '0' }} PANDAS_CI: ${{ matrix.pandas_ci || '1' }} TEST_ARGS: ${{ matrix.test_args || '' }} PYTEST_WORKERS: ${{ matrix.pytest_workers || 'auto' }} @@ -111,7 +94,7 @@ jobs: QT_QPA_PLATFORM: offscreen concurrency: # https://github.community/t/concurrecy-not-work-for-push/183068/7 - group: ${{ github.event_name == 'push' && github.run_number || github.ref }}-${{ matrix.env_file }}-${{ matrix.pattern }}-${{ matrix.extra_apt || '' }}-${{ matrix.pandas_copy_on_write || '' }} + group: ${{ github.event_name == 'push' && github.run_number || github.ref }}-${{ matrix.env_file }}-${{ matrix.pattern }}-${{ matrix.extra_apt || '' }}} cancel-in-progress: true services: diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 7ad3dd509a041..14ff227b805dd 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -71,7 +71,6 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then MSG='Partially validate docstrings (PR02)' ; echo $MSG $BASE_DIR/scripts/validate_docstrings.py --format=actions --errors=PR02 --ignore_functions \ - pandas.io.formats.style.Styler.to_excel\ pandas.CategoricalIndex.rename_categories\ pandas.CategoricalIndex.reorder_categories\ pandas.CategoricalIndex.add_categories\ diff --git a/doc/source/user_guide/merging.rst b/doc/source/user_guide/merging.rst index c9c8478a719f0..1edf3908936db 100644 --- a/doc/source/user_guide/merging.rst +++ b/doc/source/user_guide/merging.rst @@ -249,7 +249,7 @@ a :class:`MultiIndex`) associate specific keys with each original :class:`DataFr p.plot(frames, result, labels=["df1", "df2", "df3"], vertical=True) plt.close("all"); -The ``keys`` argument cane override the column names +The ``keys`` argument can override the column names when creating a new :class:`DataFrame` based on existing :class:`Series`. .. ipython:: python diff --git a/doc/source/whatsnew/v2.2.1.rst b/doc/source/whatsnew/v2.2.1.rst index 13d5024b5a131..3cc11974b14e5 100644 --- a/doc/source/whatsnew/v2.2.1.rst +++ b/doc/source/whatsnew/v2.2.1.rst @@ -20,6 +20,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.loc` raising ``IndexError`` for non-unique, masked dtype indexes where result has more than 10,000 rows (:issue:`57027`) - Fixed regression in :meth:`DataFrame.sort_index` not producing a stable sort for a index with duplicates (:issue:`57151`) - Fixed regression in :meth:`DataFrame.to_dict` with ``orient='list'`` and datetime or timedelta types returning integers (:issue:`54824`) +- Fixed regression in :meth:`DataFrame.to_json` converting nullable integers to floats (:issue:`57224`) - Fixed regression in :meth:`DataFrameGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmax` ignoring the ``skipna`` argument (:issue:`57040`) - Fixed regression in :meth:`DataFrameGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmax` where values containing the minimum or maximum value for the dtype could produce incorrect results (:issue:`57040`) - Fixed regression in :meth:`Index.join` raising ``TypeError`` when joining an empty index to a non-empty index containing mixed dtype values (:issue:`57048`) diff --git a/pandas/_config/__init__.py b/pandas/_config/__init__.py index 0594d1c190a72..9784303fc0b87 100644 --- a/pandas/_config/__init__.py +++ b/pandas/_config/__init__.py @@ -15,7 +15,6 @@ "option_context", "options", "using_copy_on_write", - "warn_copy_on_write", ] from pandas._config import config from pandas._config import dates # pyright: ignore[reportUnusedImport] # noqa: F401 @@ -35,10 +34,6 @@ def using_copy_on_write() -> bool: return True -def warn_copy_on_write() -> bool: - return False - - def using_nullable_dtypes() -> bool: _mode_options = _global_config["mode"] return _mode_options["nullable_dtypes"] diff --git a/pandas/conftest.py b/pandas/conftest.py index db251a07aeb5d..54d7122cd73de 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -1966,14 +1966,6 @@ def using_copy_on_write() -> bool: return True -@pytest.fixture -def warn_copy_on_write() -> bool: - """ - Fixture to check if Copy-on-Write is in warning mode. - """ - return False - - @pytest.fixture def using_infer_string() -> bool: """ diff --git a/pandas/core/arrays/arrow/array.py b/pandas/core/arrays/arrow/array.py index 7bab8c9395ac6..32044d1fc233a 100644 --- a/pandas/core/arrays/arrow/array.py +++ b/pandas/core/arrays/arrow/array.py @@ -1364,6 +1364,11 @@ def _to_timedeltaarray(self) -> TimedeltaArray: np_array = np_array.astype(np_dtype) return TimedeltaArray._simple_new(np_array, dtype=np_dtype) + def _values_for_json(self) -> np.ndarray: + if is_numeric_dtype(self.dtype): + return np.asarray(self, dtype=object) + return super()._values_for_json() + @doc(ExtensionArray.to_numpy) def to_numpy( self, diff --git a/pandas/core/arrays/masked.py b/pandas/core/arrays/masked.py index d5ae6a6025029..f04c50251f19e 100644 --- a/pandas/core/arrays/masked.py +++ b/pandas/core/arrays/masked.py @@ -431,6 +431,9 @@ def __abs__(self) -> Self: # ------------------------------------------------------------------ + def _values_for_json(self) -> np.ndarray: + return np.asarray(self, dtype=object) + def to_numpy( self, dtype: npt.DTypeLike | None = None, diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 207e3e7635cac..b8b5df6e5145b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -42,7 +42,6 @@ from pandas._config import ( get_option, using_copy_on_write, - warn_copy_on_write, ) from pandas._libs import ( @@ -64,7 +63,6 @@ _chained_assignment_method_msg, _chained_assignment_msg, _chained_assignment_warning_method_msg, - _chained_assignment_warning_msg, ) from pandas.util._decorators import ( Appender, @@ -4199,17 +4197,6 @@ def __setitem__(self, key, value) -> None: warnings.warn( _chained_assignment_msg, ChainedAssignmentError, stacklevel=2 ) - elif not PYPY and not using_copy_on_write(): - if sys.getrefcount(self) <= 3 and ( - warn_copy_on_write() - or ( - not warn_copy_on_write() - and any(b.refs.has_reference() for b in self._mgr.blocks) - ) - ): - warnings.warn( - _chained_assignment_warning_msg, FutureWarning, stacklevel=2 - ) key = com.apply_if_callable(key, self) @@ -4550,7 +4537,7 @@ def _clear_item_cache(self) -> None: def _get_item_cache(self, item: Hashable) -> Series: """Return the cached item, item represents a label indexer.""" - if using_copy_on_write() or warn_copy_on_write(): + if using_copy_on_write(): loc = self.columns.get_loc(item) return self._ixs(loc, axis=1) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index f53dddb25861f..0ca46f9987859 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -30,7 +30,6 @@ from pandas._config import ( config, using_copy_on_write, - warn_copy_on_write, ) from pandas._libs import lib @@ -105,7 +104,6 @@ from pandas.errors.cow import ( _chained_assignment_method_msg, _chained_assignment_warning_method_msg, - _check_cacher, ) from pandas.util._decorators import ( deprecate_nonkeyword_arguments, @@ -220,6 +218,8 @@ from pandas.core.indexers.objects import BaseIndexer from pandas.core.resample import Resampler +import textwrap + # goal is to be able to define the docs close to function, while still being # able to share _shared_docs = {**_shared_docs} @@ -2225,6 +2225,12 @@ def _repr_data_resource_(self): klass="object", storage_options=_shared_docs["storage_options"], storage_options_versionadded="1.2.0", + extra_parameters=textwrap.dedent( + """\ + engine_kwargs : dict, optional + Arbitrary keyword arguments passed to excel engine. + """ + ), ) def to_excel( self, @@ -2300,9 +2306,7 @@ def to_excel( {storage_options} .. versionadded:: {storage_options_versionadded} - engine_kwargs : dict, optional - Arbitrary keyword arguments passed to excel engine. - + {extra_parameters} See Also -------- to_csv : Write DataFrame to a comma-separated values (csv) file. @@ -4386,7 +4390,7 @@ def _check_setitem_copy(self, t: str = "setting", force: bool_t = False) -> None df.iloc[0:5]['group'] = 'a' """ - if using_copy_on_write() or warn_copy_on_write(): + if using_copy_on_write(): return # return early if the check is not needed @@ -7235,22 +7239,6 @@ def fillna( ChainedAssignmentError, stacklevel=2, ) - elif ( - not PYPY - and not using_copy_on_write() - and self._is_view_after_cow_rules() - ): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if isinstance(self, ABCSeries) and _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) value, method = validate_fillna_kwargs(value, method) if method is not None: @@ -7538,22 +7526,6 @@ def ffill( ChainedAssignmentError, stacklevel=2, ) - elif ( - not PYPY - and not using_copy_on_write() - and self._is_view_after_cow_rules() - ): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if isinstance(self, ABCSeries) and _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) return self._pad_or_backfill( "ffill", @@ -7742,22 +7714,6 @@ def bfill( ChainedAssignmentError, stacklevel=2, ) - elif ( - not PYPY - and not using_copy_on_write() - and self._is_view_after_cow_rules() - ): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if isinstance(self, ABCSeries) and _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) return self._pad_or_backfill( "bfill", @@ -7913,26 +7869,6 @@ def replace( ChainedAssignmentError, stacklevel=2, ) - elif ( - not PYPY - and not using_copy_on_write() - and self._is_view_after_cow_rules() - ): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if isinstance(self, ABCSeries) and _check_cacher(self): - # in non-CoW mode, chained Series access will populate the - # `_item_cache` which results in an increased ref count not below - # the threshold, while we still need to warn. We detect this case - # of a Series derived from a DataFrame through the presence of - # checking the `_cacher` - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) if not is_bool(regex) and to_replace is not None: raise ValueError("'to_replace' must be 'None' if 'regex' is not a bool") @@ -8363,22 +8299,6 @@ def interpolate( ChainedAssignmentError, stacklevel=2, ) - elif ( - not PYPY - and not using_copy_on_write() - and self._is_view_after_cow_rules() - ): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if isinstance(self, ABCSeries) and _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) axis = self._get_axis_number(axis) @@ -10548,7 +10468,6 @@ def _where( inplace: bool_t = False, axis: Axis | None = None, level=None, - warn: bool_t = True, ): """ Equivalent to public method `where`, except that `other` is not @@ -10679,7 +10598,7 @@ def _where( # we may have different type blocks come out of putmask, so # reconstruct the block manager - new_data = self._mgr.putmask(mask=cond, new=other, align=align, warn=warn) + new_data = self._mgr.putmask(mask=cond, new=other, align=align) result = self._constructor_from_mgr(new_data, axes=new_data.axes) return self._update_inplace(result) @@ -12545,29 +12464,8 @@ def _inplace_method(self, other, op) -> Self: """ Wrap arithmetic method to operate inplace. """ - warn = True - if not PYPY and warn_copy_on_write(): - if sys.getrefcount(self) <= REF_COUNT + 2: - # we are probably in an inplace setitem context (e.g. df['a'] += 1) - warn = False - result = op(self, other) - if ( - self.ndim == 1 - and result._indexed_same(self) - and result.dtype == self.dtype - and not using_copy_on_write() - and not (warn_copy_on_write() and not warn) - ): - # GH#36498 this inplace op can _actually_ be inplace. - # Item "BlockManager" of "Union[BlockManager, SingleBlockManager]" has - # no attribute "setitem_inplace" - self._mgr.setitem_inplace( # type: ignore[union-attr] - slice(None), result._values, warn=warn - ) - return self - # Delete cacher self._reset_cacher() diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py index f377c9d03d05a..1e6658e5dfd39 100644 --- a/pandas/core/groupby/grouper.py +++ b/pandas/core/groupby/grouper.py @@ -12,10 +12,7 @@ import numpy as np -from pandas._config import ( - using_copy_on_write, - warn_copy_on_write, -) +from pandas._config import using_copy_on_write from pandas._libs.tslibs import OutOfBoundsDatetime from pandas.errors import InvalidIndexError @@ -962,7 +959,7 @@ def is_in_axis(key) -> bool: def is_in_obj(gpr) -> bool: if not hasattr(gpr, "name"): return False - if using_copy_on_write() or warn_copy_on_write(): + if using_copy_on_write(): # For the CoW case, we check the references to determine if the # series is part of the object try: diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 24f3ff4279a84..b58c3179dec09 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -13,10 +13,7 @@ import numpy as np -from pandas._config import ( - using_copy_on_write, - warn_copy_on_write, -) +from pandas._config import using_copy_on_write from pandas._libs.indexing import NDFrameIndexerBase from pandas._libs.lib import item_from_zerodim @@ -28,11 +25,7 @@ InvalidIndexError, LossySetitemError, ) -from pandas.errors.cow import ( - _chained_assignment_msg, - _chained_assignment_warning_msg, - _check_cacher, -) +from pandas.errors.cow import _chained_assignment_msg from pandas.util._decorators import doc from pandas.util._exceptions import find_stack_level @@ -889,16 +882,6 @@ def __setitem__(self, key, value) -> None: warnings.warn( _chained_assignment_msg, ChainedAssignmentError, stacklevel=2 ) - elif not PYPY and not using_copy_on_write(): - ctr = sys.getrefcount(self.obj) - ref_count = 2 - if not warn_copy_on_write() and _check_cacher(self.obj): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_msg, FutureWarning, stacklevel=2 - ) check_dict_or_set_indexers(key) if isinstance(key, tuple): diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 1237c5b86d298..bb65e7a4d0838 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -19,7 +19,6 @@ from pandas._config import ( get_option, using_copy_on_write, - warn_copy_on_write, ) from pandas._libs import ( @@ -834,7 +833,6 @@ def replace( # mask may be pre-computed if we're called from replace_list mask: npt.NDArray[np.bool_] | None = None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: """ replace the to_replace value with value, possible to create new @@ -879,19 +877,6 @@ def replace( # and rest? blk = self._maybe_copy(using_cow, inplace) putmask_inplace(blk.values, mask, value) - if ( - inplace - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True if not (self.is_object and value is None): # if the user *explicitly* gave None, we keep None, otherwise @@ -953,7 +938,6 @@ def _replace_regex( inplace: bool = False, mask=None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: """ Replace elements by the given value. @@ -988,20 +972,6 @@ def _replace_regex( replace_regex(block.values, rx, value, mask) - if ( - inplace - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True - nbs = block.convert(copy=False, using_cow=using_cow) opt = get_option("future.no_silent_downcasting") if (len(nbs) > 1 or nbs[0].dtype != block.dtype) and not opt: @@ -1026,7 +996,6 @@ def replace_list( inplace: bool = False, regex: bool = False, using_cow: bool = False, - already_warned=None, ) -> list[Block]: """ See BlockManager.replace_list docstring. @@ -1083,20 +1052,6 @@ def replace_list( else: rb = [self if inplace else self.copy()] - if ( - inplace - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True - opt = get_option("future.no_silent_downcasting") for i, ((src, dest), mask) in enumerate(zip(pairs, masks)): convert = i == src_len # only convert once at the end @@ -1428,9 +1383,7 @@ def setitem(self, indexer, value, using_cow: bool = False) -> Block: values[indexer] = casted return self - def putmask( - self, mask, new, using_cow: bool = False, already_warned=None - ) -> list[Block]: + def putmask(self, mask, new, using_cow: bool = False) -> list[Block]: """ putmask the data to the block; it is possible that we may create a new dtype of block @@ -1463,19 +1416,6 @@ def putmask( return [self.copy(deep=False)] return [self] - if ( - warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True - try: casted = np_can_hold_element(values.dtype, new) @@ -1640,7 +1580,6 @@ def fillna( inplace: bool = False, downcast=None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: """ fillna on the block with the value. If we fail, then convert to @@ -1676,9 +1615,7 @@ def fillna( mask[mask.cumsum(self.ndim - 1) > limit] = False if inplace: - nbs = self.putmask( - mask.T, value, using_cow=using_cow, already_warned=already_warned - ) + nbs = self.putmask(mask.T, value, using_cow=using_cow) else: # without _downcast, we would break # test_fillna_dtype_conversion_equiv_replace @@ -1706,7 +1643,6 @@ def pad_or_backfill( limit_area: Literal["inside", "outside"] | None = None, downcast: Literal["infer"] | None = None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: if not self._can_hold_na: # If there are no NAs, then interpolate is a no-op @@ -1727,19 +1663,6 @@ def pad_or_backfill( limit_area=limit_area, copy=copy, ) - if ( - not copy - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True if axis == 1: new_values = new_values.T @@ -1760,7 +1683,6 @@ def interpolate( limit_area: Literal["inside", "outside"] | None = None, downcast: Literal["infer"] | None = None, using_cow: bool = False, - already_warned=None, **kwargs, ) -> list[Block]: inplace = validate_bool_kwarg(inplace, "inplace") @@ -1799,20 +1721,6 @@ def interpolate( ) data = extract_array(new_values, extract_numpy=True) - if ( - not copy - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True - nb = self.make_block_same_class(data, refs=refs) return nb._maybe_downcast([nb], downcast, using_cow, caller="interpolate") @@ -2141,9 +2049,7 @@ def where( return [nb] @final - def putmask( - self, mask, new, using_cow: bool = False, already_warned=None - ) -> list[Block]: + def putmask(self, mask, new, using_cow: bool = False) -> list[Block]: """ See Block.putmask.__doc__ """ @@ -2161,19 +2067,6 @@ def putmask( return [self.copy(deep=False)] return [self] - if ( - warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True - self = self._maybe_copy(using_cow, inplace=True) values = self.values if values.ndim == 2: @@ -2257,7 +2150,6 @@ def pad_or_backfill( limit_area: Literal["inside", "outside"] | None = None, downcast: Literal["infer"] | None = None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: values = self.values @@ -2300,7 +2192,6 @@ def fillna( inplace: bool = False, downcast=None, using_cow: bool = False, - already_warned=None, ) -> list[Block]: if isinstance(self.dtype, IntervalDtype): # Block.fillna handles coercion (test_fillna_interval) @@ -2310,7 +2201,6 @@ def fillna( inplace=inplace, downcast=downcast, using_cow=using_cow, - already_warned=already_warned, ) if using_cow and self._can_hold_na and not self.values._hasna: refs = self.refs @@ -2338,20 +2228,6 @@ def fillna( DeprecationWarning, stacklevel=find_stack_level(), ) - else: - if ( - not copy - and warn_copy_on_write() - and already_warned is not None - and not already_warned.warned_already - ): - if self.refs.has_reference(): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - already_warned.warned_already = True nb = self.make_block_same_class(new_values, refs=refs) return nb._maybe_downcast([nb], downcast, using_cow=using_cow, caller="fillna") diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index e1a18cb79a1d6..fa54fde2ece84 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -18,10 +18,7 @@ import numpy as np -from pandas._config import ( - using_copy_on_write, - warn_copy_on_write, -) +from pandas._config import using_copy_on_write from pandas._libs import ( algos as libalgos, @@ -66,11 +63,7 @@ ) import pandas.core.algorithms as algos -from pandas.core.arrays import ( - ArrowExtensionArray, - ArrowStringArray, - DatetimeArray, -) +from pandas.core.arrays import DatetimeArray from pandas.core.arrays._mixins import NDArrayBackedExtensionArray from pandas.core.base import PandasObject from pandas.core.construction import ( @@ -84,8 +77,6 @@ ensure_index, ) from pandas.core.internals.blocks import ( - COW_WARNING_GENERAL_MSG, - COW_WARNING_SETITEM_MSG, Block, NumpyBlock, ensure_block_shape, @@ -146,16 +137,6 @@ def ensure_np_dtype(dtype: DtypeObj) -> np.dtype: return dtype -class _AlreadyWarned: - def __init__(self) -> None: - # This class is used on the manager level to the block level to - # ensure that we warn only once. The block method can update the - # warned_already option without returning a value to keep the - # interface consistent. This is only a temporary solution for - # CoW warnings. - self.warned_already = False - - class BaseBlockManager(PandasObject): """ Core internal data structure to implement DataFrame, Series, etc. @@ -490,7 +471,6 @@ def fillna(self, value, limit: int | None, inplace: bool, downcast) -> Self: inplace=inplace, downcast=downcast, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) @final @@ -510,26 +490,19 @@ def where(self, other, cond, align: bool) -> Self: ) @final - def putmask(self, mask, new, align: bool = True, warn: bool = True) -> Self: + def putmask(self, mask, new, align: bool = True) -> Self: if align: align_keys = ["new", "mask"] else: align_keys = ["mask"] new = extract_array(new, extract_numpy=True) - already_warned = None - if warn_copy_on_write(): - already_warned = _AlreadyWarned() - if not warn: - already_warned.warned_already = True - return self.apply( "putmask", align_keys=align_keys, mask=mask, new=new, using_cow=using_copy_on_write(), - already_warned=already_warned, ) @final @@ -552,7 +525,6 @@ def replace(self, to_replace, value, inplace: bool) -> Self: value=value, inplace=inplace, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) @final @@ -561,7 +533,6 @@ def replace_regex(self, **kwargs) -> Self: "_replace_regex", **kwargs, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) @final @@ -582,7 +553,6 @@ def replace_list( inplace=inplace, regex=regex, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) bm._consolidate_inplace() return bm @@ -593,7 +563,6 @@ def interpolate(self, inplace: bool, **kwargs) -> Self: inplace=inplace, **kwargs, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) def pad_or_backfill(self, inplace: bool, **kwargs) -> Self: @@ -602,7 +571,6 @@ def pad_or_backfill(self, inplace: bool, **kwargs) -> Self: inplace=inplace, **kwargs, using_cow=using_copy_on_write(), - already_warned=_AlreadyWarned(), ) def shift(self, periods: int, fill_value) -> Self: @@ -611,7 +579,7 @@ def shift(self, periods: int, fill_value) -> Self: return self.apply("shift", periods=periods, fill_value=fill_value) - def setitem(self, indexer, value, warn: bool = True) -> Self: + def setitem(self, indexer, value) -> Self: """ Set values with indexer. @@ -620,14 +588,7 @@ def setitem(self, indexer, value, warn: bool = True) -> Self: if isinstance(indexer, np.ndarray) and indexer.ndim > self.ndim: raise ValueError(f"Cannot set values with ndim > {self.ndim}") - if warn and warn_copy_on_write() and not self._has_no_reference(0): - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - - elif using_copy_on_write() and not self._has_no_reference(0): + if using_copy_on_write() and not self._has_no_reference(0): # this method is only called if there is a single block -> hardcoded 0 # Split blocks to only copy the columns we want to modify if self.ndim == 2 and isinstance(indexer, tuple): @@ -1576,17 +1537,7 @@ def column_setitem( This is a method on the BlockManager level, to avoid creating an intermediate Series at the DataFrame level (`s = df[loc]; s[idx] = value`) """ - needs_to_warn = False - if warn_copy_on_write() and not self._has_no_reference(loc): - if not isinstance( - self.blocks[self.blknos[loc]].values, - (ArrowExtensionArray, ArrowStringArray), - ): - # We might raise if we are in an expansion case, so defer - # warning till we actually updated - needs_to_warn = True - - elif using_copy_on_write() and not self._has_no_reference(loc): + if using_copy_on_write() and not self._has_no_reference(loc): blkno = self.blknos[loc] # Split blocks to only copy the column we want to modify blk_loc = self.blklocs[loc] @@ -1609,13 +1560,6 @@ def column_setitem( new_mgr = col_mgr.setitem((idx,), value) self.iset(loc, new_mgr._block.values, inplace=True) - if needs_to_warn: - warnings.warn( - COW_WARNING_GENERAL_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) - def insert(self, loc: int, item: Hashable, value: ArrayLike, refs=None) -> None: """ Insert item at selected position. @@ -2298,7 +2242,7 @@ def get_numeric_data(self) -> Self: def _can_hold_na(self) -> bool: return self._block._can_hold_na - def setitem_inplace(self, indexer, value, warn: bool = True) -> None: + def setitem_inplace(self, indexer, value) -> None: """ Set values with indexer. @@ -2309,17 +2253,10 @@ def setitem_inplace(self, indexer, value, warn: bool = True) -> None: the dtype. """ using_cow = using_copy_on_write() - warn_cow = warn_copy_on_write() - if (using_cow or warn_cow) and not self._has_no_reference(0): + if using_cow and not self._has_no_reference(0): if using_cow: self.blocks = (self._block.copy(),) self._cache.clear() - elif warn_cow and warn: - warnings.warn( - COW_WARNING_SETITEM_MSG, - FutureWarning, - stacklevel=find_stack_level(), - ) arr = self.array diff --git a/pandas/core/series.py b/pandas/core/series.py index ba198a27b98f3..d30efd0e27480 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -26,10 +26,7 @@ import numpy as np -from pandas._config import ( - using_copy_on_write, - warn_copy_on_write, -) +from pandas._config import using_copy_on_write from pandas._libs import ( lib, @@ -48,9 +45,6 @@ from pandas.errors.cow import ( _chained_assignment_method_msg, _chained_assignment_msg, - _chained_assignment_warning_method_msg, - _chained_assignment_warning_msg, - _check_cacher, ) from pandas.util._decorators import ( Appender, @@ -1075,7 +1069,7 @@ def __getitem__(self, key): key = com.apply_if_callable(key, self) if key is Ellipsis: - if using_copy_on_write() or warn_copy_on_write(): + if using_copy_on_write(): return self.copy(deep=False) return self @@ -1237,29 +1231,11 @@ def _get_value(self, label, takeable: bool = False): return self.iloc[loc] def __setitem__(self, key, value) -> None: - warn = True if not PYPY and using_copy_on_write(): if sys.getrefcount(self) <= 3: warnings.warn( _chained_assignment_msg, ChainedAssignmentError, stacklevel=2 ) - elif not PYPY and not using_copy_on_write(): - ctr = sys.getrefcount(self) - ref_count = 3 - if not warn_copy_on_write() and _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count and ( - warn_copy_on_write() - or ( - not warn_copy_on_write() - and self._mgr.blocks[0].refs.has_reference() - ) - ): - warn = False - warnings.warn( - _chained_assignment_warning_msg, FutureWarning, stacklevel=2 - ) check_dict_or_set_indexers(key) key = com.apply_if_callable(key, self) @@ -1270,10 +1246,10 @@ def __setitem__(self, key, value) -> None: if isinstance(key, slice): indexer = self.index._convert_slice_indexer(key, kind="getitem") - return self._set_values(indexer, value, warn=warn) + return self._set_values(indexer, value) try: - self._set_with_engine(key, value, warn=warn) + self._set_with_engine(key, value) except KeyError: # We have a scalar (or for MultiIndex or object-dtype, scalar-like) # key that is not present in self.index. @@ -1332,25 +1308,25 @@ def __setitem__(self, key, value) -> None: # otherwise with listlike other we interpret series[mask] = other # as series[mask] = other[mask] try: - self._where(~key, value, inplace=True, warn=warn) + self._where(~key, value, inplace=True) except InvalidIndexError: # test_where_dups self.iloc[key] = value return else: - self._set_with(key, value, warn=warn) + self._set_with(key, value) if cacher_needs_updating: self._maybe_update_cacher(inplace=True) - def _set_with_engine(self, key, value, warn: bool = True) -> None: + def _set_with_engine(self, key, value) -> None: loc = self.index.get_loc(key) # this is equivalent to self._values[key] = value - self._mgr.setitem_inplace(loc, value, warn=warn) + self._mgr.setitem_inplace(loc, value) - def _set_with(self, key, value, warn: bool = True) -> None: + def _set_with(self, key, value) -> None: # We got here via exception-handling off of InvalidIndexError, so # key should always be listlike at this point. assert not isinstance(key, tuple) @@ -1361,7 +1337,7 @@ def _set_with(self, key, value, warn: bool = True) -> None: if not self.index._should_fallback_to_positional: # Regardless of the key type, we're treating it as labels - self._set_labels(key, value, warn=warn) + self._set_labels(key, value) else: # Note: key_type == "boolean" should not occur because that @@ -1378,23 +1354,23 @@ def _set_with(self, key, value, warn: bool = True) -> None: FutureWarning, stacklevel=find_stack_level(), ) - self._set_values(key, value, warn=warn) + self._set_values(key, value) else: - self._set_labels(key, value, warn=warn) + self._set_labels(key, value) - def _set_labels(self, key, value, warn: bool = True) -> None: + def _set_labels(self, key, value) -> None: key = com.asarray_tuplesafe(key) indexer: np.ndarray = self.index.get_indexer(key) mask = indexer == -1 if mask.any(): raise KeyError(f"{key[mask]} not in index") - self._set_values(indexer, value, warn=warn) + self._set_values(indexer, value) - def _set_values(self, key, value, warn: bool = True) -> None: + def _set_values(self, key, value) -> None: if isinstance(key, (Index, Series)): key = key._values - self._mgr = self._mgr.setitem(indexer=key, value=value, warn=warn) + self._mgr = self._mgr.setitem(indexer=key, value=value) self._maybe_update_cacher() def _set_value(self, label, value, takeable: bool = False) -> None: @@ -3594,18 +3570,6 @@ def update(self, other: Series | Sequence | Mapping) -> None: ChainedAssignmentError, stacklevel=2, ) - elif not PYPY and not using_copy_on_write() and self._is_view_after_cow_rules(): - ctr = sys.getrefcount(self) - ref_count = REF_COUNT - if _check_cacher(self): - # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 - ref_count += 1 - if ctr <= ref_count: - warnings.warn( - _chained_assignment_warning_method_msg, - FutureWarning, - stacklevel=2, - ) if not isinstance(other, Series): other = Series(other) @@ -4755,11 +4719,7 @@ def transform( ) -> DataFrame | Series: # Validate axis argument self._get_axis_number(axis) - ser = ( - self.copy(deep=False) - if using_copy_on_write() or warn_copy_on_write() - else self - ) + ser = self.copy(deep=False) if using_copy_on_write() else self result = SeriesApply(ser, func=func, args=args, kwargs=kwargs).transform() return result diff --git a/pandas/errors/cow.py b/pandas/errors/cow.py index 2215ec2148757..9a3f6f4cc8efc 100644 --- a/pandas/errors/cow.py +++ b/pandas/errors/cow.py @@ -1,5 +1,3 @@ -from typing import Any - _chained_assignment_msg = ( "A value is trying to be set on a copy of a DataFrame or Series " "through chained assignment.\n" @@ -54,21 +52,3 @@ "df[col] = df[col].method(value) instead, to perform " "the operation inplace on the original object.\n\n" ) - - -def _check_cacher(obj: Any) -> bool: - # This is a mess, selection paths that return a view set the _cacher attribute - # on the Series; most of them also set _item_cache which adds 1 to our relevant - # reference count, but iloc does not, so we have to check if we are actually - # in the item cache - if hasattr(obj, "_cacher"): - parent = obj._cacher[1]() - # parent could be dead - if parent is None: - return False - if hasattr(parent, "_item_cache"): - if obj._cacher[0] in parent._item_cache: - # Check if we are actually the item from item_cache, iloc creates a - # new object - return obj is parent._item_cache[obj._cacher[0]] - return False diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 0e67949709a22..3a6a44a8be253 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -516,6 +516,7 @@ def set_tooltips( klass="Styler", storage_options=_shared_docs["storage_options"], storage_options_versionadded="1.5.0", + extra_parameters="", ) def to_excel( self, diff --git a/pandas/tests/apply/test_frame_apply.py b/pandas/tests/apply/test_frame_apply.py index 66a43f2ba4bcd..c35f9bf13200f 100644 --- a/pandas/tests/apply/test_frame_apply.py +++ b/pandas/tests/apply/test_frame_apply.py @@ -1487,7 +1487,7 @@ def test_apply_dtype(col): tm.assert_series_equal(result, expected) -def test_apply_mutating(using_copy_on_write, warn_copy_on_write): +def test_apply_mutating(using_copy_on_write): # GH#35462 case where applied func pins a new BlockManager to a row df = DataFrame({"a": range(100), "b": range(100, 200)}) df_orig = df.copy() @@ -1501,8 +1501,7 @@ def func(row): expected = df.copy() expected["a"] += 1 - with tm.assert_cow_warning(warn_copy_on_write): - result = df.apply(func, axis=1) + result = df.apply(func, axis=1) tm.assert_frame_equal(result, expected) if using_copy_on_write: diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index b69fb573987f9..7b1f8b22301a1 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -1290,7 +1290,7 @@ def test_assignment_not_inplace(self): expected["c"] = expected["a"] + expected["b"] tm.assert_frame_equal(df, expected) - def test_multi_line_expression(self, warn_copy_on_write): + def test_multi_line_expression(self): # GH 11149 df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) expected = df.copy() @@ -1964,15 +1964,14 @@ def test_eval_no_support_column_name(request, column): tm.assert_frame_equal(result, expected) -def test_set_inplace(using_copy_on_write, warn_copy_on_write): +def test_set_inplace(using_copy_on_write): # https://github.com/pandas-dev/pandas/issues/47449 # Ensure we don't only update the DataFrame inplace, but also the actual # column values, such that references to this column also get updated df = DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]}) result_view = df[:] ser = df["A"] - with tm.assert_cow_warning(warn_copy_on_write): - df.eval("A = B + C", inplace=True) + df.eval("A = B + C", inplace=True) expected = DataFrame({"A": [11, 13, 15], "B": [4, 5, 6], "C": [7, 8, 9]}) tm.assert_frame_equal(df, expected) if not using_copy_on_write: diff --git a/pandas/tests/copy_view/index/test_index.py b/pandas/tests/copy_view/index/test_index.py index 596379a3266fb..9a788c5fd4193 100644 --- a/pandas/tests/copy_view/index/test_index.py +++ b/pandas/tests/copy_view/index/test_index.py @@ -19,12 +19,11 @@ def index_view(index_data): return idx, view -def test_set_index_update_column(using_copy_on_write, warn_copy_on_write): +def test_set_index_update_column(using_copy_on_write): df = DataFrame({"a": [1, 2], "b": 1}) df = df.set_index("a", drop=False) expected = df.index.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100 + df.iloc[0, 0] = 100 if using_copy_on_write: tm.assert_index_equal(df.index, expected) else: @@ -40,53 +39,49 @@ def test_set_index_drop_update_column(using_copy_on_write): tm.assert_index_equal(df.index, expected) -def test_set_index_series(using_copy_on_write, warn_copy_on_write): +def test_set_index_series(using_copy_on_write): df = DataFrame({"a": [1, 2], "b": 1.5}) ser = Series([10, 11]) df = df.set_index(ser) expected = df.index.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 100 + ser.iloc[0] = 100 if using_copy_on_write: tm.assert_index_equal(df.index, expected) else: tm.assert_index_equal(df.index, Index([100, 11])) -def test_assign_index_as_series(using_copy_on_write, warn_copy_on_write): +def test_assign_index_as_series(using_copy_on_write): df = DataFrame({"a": [1, 2], "b": 1.5}) ser = Series([10, 11]) df.index = ser expected = df.index.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 100 + ser.iloc[0] = 100 if using_copy_on_write: tm.assert_index_equal(df.index, expected) else: tm.assert_index_equal(df.index, Index([100, 11])) -def test_assign_index_as_index(using_copy_on_write, warn_copy_on_write): +def test_assign_index_as_index(using_copy_on_write): df = DataFrame({"a": [1, 2], "b": 1.5}) ser = Series([10, 11]) rhs_index = Index(ser) df.index = rhs_index rhs_index = None # overwrite to clear reference expected = df.index.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 100 + ser.iloc[0] = 100 if using_copy_on_write: tm.assert_index_equal(df.index, expected) else: tm.assert_index_equal(df.index, Index([100, 11])) -def test_index_from_series(using_copy_on_write, warn_copy_on_write): +def test_index_from_series(using_copy_on_write): ser = Series([1, 2]) idx = Index(ser) expected = idx.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 100 + ser.iloc[0] = 100 if using_copy_on_write: tm.assert_index_equal(idx, expected) else: @@ -101,13 +96,12 @@ def test_index_from_series_copy(using_copy_on_write): assert np.shares_memory(get_array(ser), arr) -def test_index_from_index(using_copy_on_write, warn_copy_on_write): +def test_index_from_index(using_copy_on_write): ser = Series([1, 2]) idx = Index(ser) idx = Index(idx) expected = idx.copy(deep=True) - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 100 + ser.iloc[0] = 100 if using_copy_on_write: tm.assert_index_equal(idx, expected) else: diff --git a/pandas/tests/copy_view/test_chained_assignment_deprecation.py b/pandas/tests/copy_view/test_chained_assignment_deprecation.py index 0a37f6b813e55..cfa9cf64357b6 100644 --- a/pandas/tests/copy_view/test_chained_assignment_deprecation.py +++ b/pandas/tests/copy_view/test_chained_assignment_deprecation.py @@ -1,7 +1,6 @@ import numpy as np import pytest -from pandas.compat import PY311 from pandas.errors import ( ChainedAssignmentError, SettingWithCopyWarning, @@ -33,117 +32,11 @@ def test_methods_iloc_warn(using_copy_on_write): df.iloc[:, 0].bfill(inplace=True) -@pytest.mark.parametrize( - "func, args", - [ - ("replace", (4, 5)), - ("fillna", (1,)), - ("interpolate", ()), - ("bfill", ()), - ("ffill", ()), - ], -) -def test_methods_iloc_getitem_item_cache( - func, args, using_copy_on_write, warn_copy_on_write -): - # ensure we don't incorrectly raise chained assignment warning because - # of the item cache / iloc not setting the item cache - df_orig = DataFrame({"a": [1, 2, 3], "b": 1}) - - df = df_orig.copy() - ser = df.iloc[:, 0] - getattr(ser, func)(*args, inplace=True) - - # parent that holds item_cache is dead, so don't increase ref count - df = df_orig.copy() - ser = df.copy()["a"] - getattr(ser, func)(*args, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - ser = df.iloc[:, 0] # iloc creates a new object - getattr(ser, func)(*args, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - ser = df["a"] - getattr(ser, func)(*args, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - # TODO(CoW-warn) because of the usage of *args, this doesn't warn on Py3.11+ - if using_copy_on_write: - with tm.raises_chained_assignment_error(not PY311): - getattr(df["a"], func)(*args, inplace=True) - else: - with tm.assert_cow_warning(not PY311, match="A value"): - getattr(df["a"], func)(*args, inplace=True) - - df = df_orig.copy() - ser = df["a"] # populate the item_cache and keep ref - if using_copy_on_write: - with tm.raises_chained_assignment_error(not PY311): - getattr(df["a"], func)(*args, inplace=True) - else: - # ideally also warns on the default mode, but the ser' _cacher - # messes up the refcount + even in warning mode this doesn't trigger - # the warning of Py3.1+ (see above) - with tm.assert_cow_warning(warn_copy_on_write and not PY311, match="A value"): - getattr(df["a"], func)(*args, inplace=True) - - -def test_methods_iloc_getitem_item_cache_fillna( - using_copy_on_write, warn_copy_on_write -): - # ensure we don't incorrectly raise chained assignment warning because - # of the item cache / iloc not setting the item cache - df_orig = DataFrame({"a": [1, 2, 3], "b": 1}) - - df = df_orig.copy() - ser = df.iloc[:, 0] - ser.fillna(1, inplace=True) - - # parent that holds item_cache is dead, so don't increase ref count - df = df_orig.copy() - ser = df.copy()["a"] - ser.fillna(1, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - ser = df.iloc[:, 0] # iloc creates a new object - ser.fillna(1, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - ser = df["a"] - ser.fillna(1, inplace=True) - - df = df_orig.copy() - df["a"] # populate the item_cache - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - df["a"].fillna(1, inplace=True) - else: - with tm.assert_cow_warning(match="A value"): - df["a"].fillna(1, inplace=True) - - df = df_orig.copy() - ser = df["a"] # populate the item_cache and keep ref - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - df["a"].fillna(1, inplace=True) - else: - # TODO(CoW-warn) ideally also warns on the default mode, but the ser' _cacher - # messes up the refcount - with tm.assert_cow_warning(warn_copy_on_write, match="A value"): - df["a"].fillna(1, inplace=True) - - # TODO(CoW-warn) expand the cases @pytest.mark.parametrize( "indexer", [0, [0, 1], slice(0, 2), np.array([True, False, True])] ) -def test_series_setitem(indexer, using_copy_on_write, warn_copy_on_write): +def test_series_setitem(indexer, using_copy_on_write): # ensure we only get a single warning for those typical cases of chained # assignment df = DataFrame({"a": [1, 2, 3], "b": 1}) diff --git a/pandas/tests/copy_view/test_clip.py b/pandas/tests/copy_view/test_clip.py index 7c87646424e2f..9be9ba6f144c4 100644 --- a/pandas/tests/copy_view/test_clip.py +++ b/pandas/tests/copy_view/test_clip.py @@ -8,16 +8,12 @@ from pandas.tests.copy_view.util import get_array -def test_clip_inplace_reference(using_copy_on_write, warn_copy_on_write): +def test_clip_inplace_reference(using_copy_on_write): df = DataFrame({"a": [1.5, 2, 3]}) df_copy = df.copy() arr_a = get_array(df, "a") view = df[:] - if warn_copy_on_write: - with tm.assert_cow_warning(): - df.clip(lower=2, inplace=True) - else: - df.clip(lower=2, inplace=True) + df.clip(lower=2, inplace=True) if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), arr_a) diff --git a/pandas/tests/copy_view/test_constructors.py b/pandas/tests/copy_view/test_constructors.py index cbd0e6899bfc9..5f095d3d74c54 100644 --- a/pandas/tests/copy_view/test_constructors.py +++ b/pandas/tests/copy_view/test_constructors.py @@ -21,7 +21,7 @@ @pytest.mark.parametrize("dtype", [None, "int64"]) -def test_series_from_series(dtype, using_copy_on_write, warn_copy_on_write): +def test_series_from_series(dtype, using_copy_on_write): # Case: constructing a Series from another Series object follows CoW rules: # a new object is returned and thus mutations are not propagated ser = Series([1, 2, 3], name="name") @@ -43,8 +43,7 @@ def test_series_from_series(dtype, using_copy_on_write, warn_copy_on_write): assert not np.shares_memory(get_array(ser), get_array(result)) else: # mutating shallow copy does mutate original - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0] = 0 + result.iloc[0] = 0 assert ser.iloc[0] == 0 # and still shares memory assert np.shares_memory(get_array(ser), get_array(result)) @@ -58,12 +57,11 @@ def test_series_from_series(dtype, using_copy_on_write, warn_copy_on_write): assert result.iloc[0] == 1 else: # mutating original does mutate shallow copy - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 0 + ser.iloc[0] = 0 assert result.iloc[0] == 0 -def test_series_from_series_with_reindex(using_copy_on_write, warn_copy_on_write): +def test_series_from_series_with_reindex(using_copy_on_write): # Case: constructing a Series from another Series with specifying an index # that potentially requires a reindex of the values ser = Series([1, 2, 3], name="name") @@ -78,8 +76,7 @@ def test_series_from_series_with_reindex(using_copy_on_write, warn_copy_on_write ]: result = Series(ser, index=index) assert np.shares_memory(ser.values, result.values) - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0] = 0 + result.iloc[0] = 0 if using_copy_on_write: assert ser.iloc[0] == 1 else: @@ -190,9 +187,7 @@ def test_series_from_block_manager_different_dtype(using_copy_on_write): @pytest.mark.parametrize("use_mgr", [True, False]) @pytest.mark.parametrize("columns", [None, ["a"]]) -def test_dataframe_constructor_mgr_or_df( - using_copy_on_write, warn_copy_on_write, columns, use_mgr -): +def test_dataframe_constructor_mgr_or_df(using_copy_on_write, columns, use_mgr): df = DataFrame({"a": [1, 2, 3]}) df_orig = df.copy() @@ -207,8 +202,7 @@ def test_dataframe_constructor_mgr_or_df( new_df = DataFrame(data) assert np.shares_memory(get_array(df, "a"), get_array(new_df, "a")) - with tm.assert_cow_warning(warn_copy_on_write and not use_mgr): - new_df.iloc[0] = 100 + new_df.iloc[0] = 100 if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), get_array(new_df, "a")) @@ -221,9 +215,7 @@ def test_dataframe_constructor_mgr_or_df( @pytest.mark.parametrize("dtype", [None, "int64", "Int64"]) @pytest.mark.parametrize("index", [None, [0, 1, 2]]) @pytest.mark.parametrize("columns", [None, ["a", "b"], ["a", "b", "c"]]) -def test_dataframe_from_dict_of_series( - request, using_copy_on_write, warn_copy_on_write, columns, index, dtype -): +def test_dataframe_from_dict_of_series(using_copy_on_write, columns, index, dtype): # Case: constructing a DataFrame from Series objects with copy=False # has to do a lazy following CoW rules # (the default for DataFrame(dict) is still to copy to ensure consolidation) @@ -242,8 +234,7 @@ def test_dataframe_from_dict_of_series( assert np.shares_memory(get_array(result, "a"), get_array(s1)) # mutating the new dataframe doesn't mutate original - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0, 0] = 10 + result.iloc[0, 0] = 10 if using_copy_on_write: assert not np.shares_memory(get_array(result, "a"), get_array(s1)) tm.assert_series_equal(s1, s1_orig) @@ -256,8 +247,7 @@ def test_dataframe_from_dict_of_series( result = DataFrame( {"a": s1, "b": s2}, index=index, columns=columns, dtype=dtype, copy=False ) - with tm.assert_cow_warning(warn_copy_on_write): - s1.iloc[0] = 10 + s1.iloc[0] = 10 if using_copy_on_write: assert not np.shares_memory(get_array(result, "a"), get_array(s1)) tm.assert_frame_equal(result, expected) @@ -287,7 +277,7 @@ def test_dataframe_from_dict_of_series_with_reindex(dtype): "data, dtype", [([1, 2], None), ([1, 2], "int64"), (["a", "b"], None)] ) def test_dataframe_from_series_or_index( - using_copy_on_write, warn_copy_on_write, data, dtype, index_or_series + using_copy_on_write, data, dtype, index_or_series ): obj = index_or_series(data, dtype=dtype) obj_orig = obj.copy() @@ -296,8 +286,7 @@ def test_dataframe_from_series_or_index( if using_copy_on_write: assert not df._mgr._has_no_reference(0) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = data[-1] + df.iloc[0, 0] = data[-1] if using_copy_on_write: tm.assert_equal(obj, obj_orig) @@ -349,7 +338,7 @@ def test_frame_from_numpy_array(using_copy_on_write, copy): assert np.shares_memory(get_array(df, 0), arr) -def test_dataframe_from_records_with_dataframe(using_copy_on_write, warn_copy_on_write): +def test_dataframe_from_records_with_dataframe(using_copy_on_write): df = DataFrame({"a": [1, 2, 3]}) df_orig = df.copy() with tm.assert_produces_warning(FutureWarning): @@ -357,8 +346,7 @@ def test_dataframe_from_records_with_dataframe(using_copy_on_write, warn_copy_on if using_copy_on_write: assert not df._mgr._has_no_reference(0) assert np.shares_memory(get_array(df, "a"), get_array(df2, "a")) - with tm.assert_cow_warning(warn_copy_on_write): - df2.iloc[0, 0] = 100 + df2.iloc[0, 0] = 100 if using_copy_on_write: tm.assert_frame_equal(df, df_orig) else: diff --git a/pandas/tests/copy_view/test_core_functionalities.py b/pandas/tests/copy_view/test_core_functionalities.py index 8dc80c5cc0e0e..b37e1a3718ac1 100644 --- a/pandas/tests/copy_view/test_core_functionalities.py +++ b/pandas/tests/copy_view/test_core_functionalities.py @@ -28,23 +28,20 @@ def test_setitem_dont_track_unnecessary_references(using_copy_on_write): assert np.shares_memory(arr, get_array(df, "a")) -def test_setitem_with_view_copies(using_copy_on_write, warn_copy_on_write): +def test_setitem_with_view_copies(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": 1, "c": 1}) view = df[:] expected = df.copy() df["b"] = 100 arr = get_array(df, "a") - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100 # Check that we correctly track reference + df.iloc[0, 0] = 100 # Check that we correctly track reference if using_copy_on_write: assert not np.shares_memory(arr, get_array(df, "a")) tm.assert_frame_equal(view, expected) -def test_setitem_with_view_invalidated_does_not_copy( - using_copy_on_write, warn_copy_on_write, request -): +def test_setitem_with_view_invalidated_does_not_copy(using_copy_on_write, request): df = DataFrame({"a": [1, 2, 3], "b": 1, "c": 1}) view = df[:] @@ -53,8 +50,7 @@ def test_setitem_with_view_invalidated_does_not_copy( view = None # noqa: F841 # TODO(CoW-warn) false positive? -> block gets split because of `df["b"] = 100` # which introduces additional refs, even when those of `view` go out of scopes - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100 + df.iloc[0, 0] = 100 if using_copy_on_write: # Setitem split the block. Since the old block shared data with view # all the new blocks are referencing view and each other. When view diff --git a/pandas/tests/copy_view/test_indexing.py b/pandas/tests/copy_view/test_indexing.py index c35a0b89585c3..69fb8fe2c6f63 100644 --- a/pandas/tests/copy_view/test_indexing.py +++ b/pandas/tests/copy_view/test_indexing.py @@ -101,7 +101,7 @@ def test_subset_column_selection_modify_parent(backend, using_copy_on_write): tm.assert_frame_equal(subset, expected) -def test_subset_row_slice(backend, using_copy_on_write, warn_copy_on_write): +def test_subset_row_slice(backend, using_copy_on_write): # Case: taking a subset of the rows of a DataFrame using a slice # + afterwards modifying the subset _, DataFrame, _ = backend @@ -121,8 +121,7 @@ def test_subset_row_slice(backend, using_copy_on_write, warn_copy_on_write): # INFO this no longer raise warning since pandas 1.4 # with pd.option_context("chained_assignment", "warn"): # with tm.assert_produces_warning(SettingWithCopyWarning): - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0, 0] = 0 + subset.iloc[0, 0] = 0 subset._mgr._verify_integrity() @@ -140,7 +139,7 @@ def test_subset_row_slice(backend, using_copy_on_write, warn_copy_on_write): @pytest.mark.parametrize( "dtype", ["int64", "float64"], ids=["single-block", "mixed-block"] ) -def test_subset_column_slice(backend, using_copy_on_write, warn_copy_on_write, dtype): +def test_subset_column_slice(backend, using_copy_on_write, dtype): # Case: taking a subset of the columns of a DataFrame using a slice # + afterwards modifying the subset dtype_backend, DataFrame, _ = backend @@ -158,9 +157,6 @@ def test_subset_column_slice(backend, using_copy_on_write, warn_copy_on_write, d subset.iloc[0, 0] = 0 assert not np.shares_memory(get_array(subset, "b"), get_array(df, "b")) - elif warn_copy_on_write: - with tm.assert_cow_warning(single_block): - subset.iloc[0, 0] = 0 else: # we only get a warning in case of a single block warn = SettingWithCopyWarning if single_block else None @@ -198,7 +194,6 @@ def test_subset_loc_rows_columns( row_indexer, column_indexer, using_copy_on_write, - warn_copy_on_write, ): # Case: taking a subset of the rows+columns of a DataFrame using .loc # + afterwards modifying the subset @@ -223,8 +218,7 @@ def test_subset_loc_rows_columns( ) # modifying the subset never modifies the parent - with tm.assert_cow_warning(warn_copy_on_write and mutate_parent): - subset.iloc[0, 0] = 0 + subset.iloc[0, 0] = 0 expected = DataFrame( {"b": [0, 6], "c": np.array([8, 9], dtype=dtype)}, index=range(1, 3) @@ -254,7 +248,6 @@ def test_subset_iloc_rows_columns( row_indexer, column_indexer, using_copy_on_write, - warn_copy_on_write, ): # Case: taking a subset of the rows+columns of a DataFrame using .iloc # + afterwards modifying the subset @@ -279,8 +272,7 @@ def test_subset_iloc_rows_columns( ) # modifying the subset never modifies the parent - with tm.assert_cow_warning(warn_copy_on_write and mutate_parent): - subset.iloc[0, 0] = 0 + subset.iloc[0, 0] = 0 expected = DataFrame( {"b": [0, 6], "c": np.array([8, 9], dtype=dtype)}, index=range(1, 3) @@ -296,9 +288,7 @@ def test_subset_iloc_rows_columns( [slice(0, 2), np.array([True, True, False]), np.array([0, 1])], ids=["slice", "mask", "array"], ) -def test_subset_set_with_row_indexer( - backend, indexer_si, indexer, using_copy_on_write, warn_copy_on_write -): +def test_subset_set_with_row_indexer(backend, indexer_si, indexer, using_copy_on_write): # Case: setting values with a row indexer on a viewing subset # subset[indexer] = value and subset.iloc[indexer] = value _, DataFrame, _ = backend @@ -315,9 +305,6 @@ def test_subset_set_with_row_indexer( if using_copy_on_write: indexer_si(subset)[indexer] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - indexer_si(subset)[indexer] = 0 else: # INFO iloc no longer raises warning since pandas 1.4 warn = SettingWithCopyWarning if indexer_si is tm.setitem else None @@ -338,7 +325,7 @@ def test_subset_set_with_row_indexer( tm.assert_frame_equal(df, df_orig) -def test_subset_set_with_mask(backend, using_copy_on_write, warn_copy_on_write): +def test_subset_set_with_mask(backend, using_copy_on_write): # Case: setting values with a mask on a viewing subset: subset[mask] = value _, DataFrame, _ = backend df = DataFrame({"a": [1, 2, 3, 4], "b": [4, 5, 6, 7], "c": [0.1, 0.2, 0.3, 0.4]}) @@ -349,9 +336,6 @@ def test_subset_set_with_mask(backend, using_copy_on_write, warn_copy_on_write): if using_copy_on_write: subset[mask] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - subset[mask] = 0 else: with pd.option_context("chained_assignment", "warn"): with tm.assert_produces_warning(SettingWithCopyWarning): @@ -371,7 +355,7 @@ def test_subset_set_with_mask(backend, using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_subset_set_column(backend, using_copy_on_write, warn_copy_on_write): +def test_subset_set_column(backend, using_copy_on_write): # Case: setting a single column on a viewing subset -> subset[col] = value dtype_backend, DataFrame, _ = backend df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}) @@ -383,7 +367,7 @@ def test_subset_set_column(backend, using_copy_on_write, warn_copy_on_write): else: arr = pd.array([10, 11], dtype="Int64") - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: subset["a"] = arr else: with pd.option_context("chained_assignment", "warn"): @@ -401,9 +385,7 @@ def test_subset_set_column(backend, using_copy_on_write, warn_copy_on_write): @pytest.mark.parametrize( "dtype", ["int64", "float64"], ids=["single-block", "mixed-block"] ) -def test_subset_set_column_with_loc( - backend, using_copy_on_write, warn_copy_on_write, dtype -): +def test_subset_set_column_with_loc(backend, using_copy_on_write, dtype): # Case: setting a single column with loc on a viewing subset # -> subset.loc[:, col] = value _, DataFrame, _ = backend @@ -415,9 +397,6 @@ def test_subset_set_column_with_loc( if using_copy_on_write: subset.loc[:, "a"] = np.array([10, 11], dtype="int64") - elif warn_copy_on_write: - with tm.assert_cow_warning(): - subset.loc[:, "a"] = np.array([10, 11], dtype="int64") else: with pd.option_context("chained_assignment", "warn"): with tm.assert_produces_warning(None): @@ -438,7 +417,7 @@ def test_subset_set_column_with_loc( tm.assert_frame_equal(df, df_orig) -def test_subset_set_column_with_loc2(backend, using_copy_on_write, warn_copy_on_write): +def test_subset_set_column_with_loc2(backend, using_copy_on_write): # Case: setting a single column with loc on a viewing subset # -> subset.loc[:, col] = value # separate test for case of DataFrame of a single column -> takes a separate @@ -450,9 +429,6 @@ def test_subset_set_column_with_loc2(backend, using_copy_on_write, warn_copy_on_ if using_copy_on_write: subset.loc[:, "a"] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - subset.loc[:, "a"] = 0 else: with pd.option_context("chained_assignment", "warn"): with tm.assert_produces_warning(None): @@ -473,7 +449,7 @@ def test_subset_set_column_with_loc2(backend, using_copy_on_write, warn_copy_on_ @pytest.mark.parametrize( "dtype", ["int64", "float64"], ids=["single-block", "mixed-block"] ) -def test_subset_set_columns(backend, using_copy_on_write, warn_copy_on_write, dtype): +def test_subset_set_columns(backend, using_copy_on_write, dtype): # Case: setting multiple columns on a viewing subset # -> subset[[col1, col2]] = value dtype_backend, DataFrame, _ = backend @@ -483,7 +459,7 @@ def test_subset_set_columns(backend, using_copy_on_write, warn_copy_on_write, dt df_orig = df.copy() subset = df[1:3] - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: subset[["a", "c"]] = 0 else: with pd.option_context("chained_assignment", "warn"): @@ -510,9 +486,7 @@ def test_subset_set_columns(backend, using_copy_on_write, warn_copy_on_write, dt [slice("a", "b"), np.array([True, True, False]), ["a", "b"]], ids=["slice", "mask", "array"], ) -def test_subset_set_with_column_indexer( - backend, indexer, using_copy_on_write, warn_copy_on_write -): +def test_subset_set_with_column_indexer(backend, indexer, using_copy_on_write): # Case: setting multiple columns with a column indexer on a viewing subset # -> subset.loc[:, [col1, col2]] = value _, DataFrame, _ = backend @@ -522,9 +496,6 @@ def test_subset_set_with_column_indexer( if using_copy_on_write: subset.loc[:, indexer] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - subset.loc[:, indexer] = 0 else: with pd.option_context("chained_assignment", "warn"): # As of 2.0, this setitem attempts (successfully) to set values @@ -572,7 +543,6 @@ def test_subset_chained_getitem( method, dtype, using_copy_on_write, - warn_copy_on_write, ): # Case: creating a subset using multiple, chained getitem calls using views # still needs to guarantee proper CoW behaviour @@ -593,8 +563,7 @@ def test_subset_chained_getitem( # modify subset -> don't modify parent subset = method(df) - with tm.assert_cow_warning(warn_copy_on_write and subset_is_view): - subset.iloc[0, 0] = 0 + subset.iloc[0, 0] = 0 if using_copy_on_write or (not subset_is_view): tm.assert_frame_equal(df, df_orig) else: @@ -602,8 +571,7 @@ def test_subset_chained_getitem( # modify parent -> don't modify subset subset = method(df) - with tm.assert_cow_warning(warn_copy_on_write and subset_is_view): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 expected = DataFrame({"a": [1, 2], "b": [4, 5]}) if using_copy_on_write or not subset_is_view: tm.assert_frame_equal(subset, expected) @@ -614,9 +582,7 @@ def test_subset_chained_getitem( @pytest.mark.parametrize( "dtype", ["int64", "float64"], ids=["single-block", "mixed-block"] ) -def test_subset_chained_getitem_column( - backend, dtype, using_copy_on_write, warn_copy_on_write -): +def test_subset_chained_getitem_column(backend, dtype, using_copy_on_write): # Case: creating a subset using multiple, chained getitem calls using views # still needs to guarantee proper CoW behaviour dtype_backend, DataFrame, Series = backend @@ -628,8 +594,7 @@ def test_subset_chained_getitem_column( # modify subset -> don't modify parent subset = df[:]["a"][0:2] df._clear_item_cache() - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0] = 0 + subset.iloc[0] = 0 if using_copy_on_write: tm.assert_frame_equal(df, df_orig) else: @@ -638,8 +603,7 @@ def test_subset_chained_getitem_column( # modify parent -> don't modify subset subset = df[:]["a"][0:2] df._clear_item_cache() - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 expected = Series([1, 2], name="a") if using_copy_on_write: tm.assert_series_equal(subset, expected) @@ -661,9 +625,7 @@ def test_subset_chained_getitem_column( ], ids=["getitem", "iloc", "loc", "long-chain"], ) -def test_subset_chained_getitem_series( - backend, method, using_copy_on_write, warn_copy_on_write -): +def test_subset_chained_getitem_series(backend, method, using_copy_on_write): # Case: creating a subset using multiple, chained getitem calls using views # still needs to guarantee proper CoW behaviour _, _, Series = backend @@ -672,8 +634,7 @@ def test_subset_chained_getitem_series( # modify subset -> don't modify parent subset = method(s) - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0] = 0 + subset.iloc[0] = 0 if using_copy_on_write: tm.assert_series_equal(s, s_orig) else: @@ -681,8 +642,7 @@ def test_subset_chained_getitem_series( # modify parent -> don't modify subset subset = s.iloc[0:3].iloc[0:2] - with tm.assert_cow_warning(warn_copy_on_write): - s.iloc[0] = 0 + s.iloc[0] = 0 expected = Series([1, 2], index=["a", "b"]) if using_copy_on_write: tm.assert_series_equal(subset, expected) @@ -690,15 +650,14 @@ def test_subset_chained_getitem_series( assert subset.iloc[0] == 0 -def test_subset_chained_single_block_row(using_copy_on_write, warn_copy_on_write): +def test_subset_chained_single_block_row(using_copy_on_write): # not parametrizing this for dtype backend, since this explicitly tests single block df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) df_orig = df.copy() # modify subset -> don't modify parent subset = df[:].iloc[0].iloc[0:2] - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0] = 0 + subset.iloc[0] = 0 if using_copy_on_write: tm.assert_frame_equal(df, df_orig) else: @@ -706,8 +665,7 @@ def test_subset_chained_single_block_row(using_copy_on_write, warn_copy_on_write # modify parent -> don't modify subset subset = df[:].iloc[0].iloc[0:2] - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 expected = Series([1, 4], index=["a", "b"], name=0) if using_copy_on_write: tm.assert_series_equal(subset, expected) @@ -726,7 +684,7 @@ def test_subset_chained_single_block_row(using_copy_on_write, warn_copy_on_write ], ids=["getitem", "loc", "loc-rows", "iloc", "iloc-rows"], ) -def test_null_slice(backend, method, using_copy_on_write, warn_copy_on_write): +def test_null_slice(backend, method, using_copy_on_write): # Case: also all variants of indexing with a null slice (:) should return # new objects to ensure we correctly use CoW for the results dtype_backend, DataFrame, _ = backend @@ -739,8 +697,7 @@ def test_null_slice(backend, method, using_copy_on_write, warn_copy_on_write): assert df2 is not df # and those trigger CoW when mutated - with tm.assert_cow_warning(warn_copy_on_write): - df2.iloc[0, 0] = 0 + df2.iloc[0, 0] = 0 if using_copy_on_write: tm.assert_frame_equal(df, df_orig) else: @@ -756,7 +713,7 @@ def test_null_slice(backend, method, using_copy_on_write, warn_copy_on_write): ], ids=["getitem", "loc", "iloc"], ) -def test_null_slice_series(backend, method, using_copy_on_write, warn_copy_on_write): +def test_null_slice_series(backend, method, using_copy_on_write): _, _, Series = backend s = Series([1, 2, 3], index=["a", "b", "c"]) s_orig = s.copy() @@ -767,8 +724,7 @@ def test_null_slice_series(backend, method, using_copy_on_write, warn_copy_on_wr assert s2 is not s # and those trigger CoW when mutated - with tm.assert_cow_warning(warn_copy_on_write): - s2.iloc[0] = 0 + s2.iloc[0] = 0 if using_copy_on_write: tm.assert_series_equal(s, s_orig) else: @@ -782,7 +738,7 @@ def test_null_slice_series(backend, method, using_copy_on_write, warn_copy_on_wr # Series -- Indexing operations taking subset + modifying the subset/parent -def test_series_getitem_slice(backend, using_copy_on_write, warn_copy_on_write): +def test_series_getitem_slice(backend, using_copy_on_write): # Case: taking a slice of a Series + afterwards modifying the subset _, _, Series = backend s = Series([1, 2, 3], index=["a", "b", "c"]) @@ -791,8 +747,7 @@ def test_series_getitem_slice(backend, using_copy_on_write, warn_copy_on_write): subset = s[:] assert np.shares_memory(get_array(subset), get_array(s)) - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0] = 0 + subset.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(subset), get_array(s)) @@ -808,7 +763,7 @@ def test_series_getitem_slice(backend, using_copy_on_write, warn_copy_on_write): assert s.iloc[0] == 0 -def test_series_getitem_ellipsis(using_copy_on_write, warn_copy_on_write): +def test_series_getitem_ellipsis(using_copy_on_write): # Case: taking a view of a Series using Ellipsis + afterwards modifying the subset s = Series([1, 2, 3]) s_orig = s.copy() @@ -816,8 +771,7 @@ def test_series_getitem_ellipsis(using_copy_on_write, warn_copy_on_write): subset = s[...] assert np.shares_memory(get_array(subset), get_array(s)) - with tm.assert_cow_warning(warn_copy_on_write): - subset.iloc[0] = 0 + subset.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(subset), get_array(s)) @@ -839,7 +793,7 @@ def test_series_getitem_ellipsis(using_copy_on_write, warn_copy_on_write): ids=["slice", "mask", "array"], ) def test_series_subset_set_with_indexer( - backend, indexer_si, indexer, using_copy_on_write, warn_copy_on_write + backend, indexer_si, indexer, using_copy_on_write ): # Case: setting values in a viewing Series with an indexer _, _, Series = backend @@ -855,12 +809,8 @@ def test_series_subset_set_with_indexer( and indexer.dtype.kind == "i" ): warn = FutureWarning - if warn_copy_on_write: - with tm.assert_cow_warning(raise_on_extra_warnings=warn is not None): - indexer_si(subset)[indexer] = 0 - else: - with tm.assert_produces_warning(warn, match=msg): - indexer_si(subset)[indexer] = 0 + with tm.assert_produces_warning(warn, match=msg): + indexer_si(subset)[indexer] = 0 expected = Series([0, 0, 3], index=["a", "b", "c"]) tm.assert_series_equal(subset, expected) @@ -874,7 +824,7 @@ def test_series_subset_set_with_indexer( # del operator -def test_del_frame(backend, using_copy_on_write, warn_copy_on_write): +def test_del_frame(backend, using_copy_on_write): # Case: deleting a column with `del` on a viewing child dataframe should # not modify parent + update the references dtype_backend, DataFrame, _ = backend @@ -891,13 +841,11 @@ def test_del_frame(backend, using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(df2, df_orig[["a", "c"]]) df2._mgr._verify_integrity() - with tm.assert_cow_warning(warn_copy_on_write and dtype_backend == "numpy"): - df.loc[0, "b"] = 200 + df.loc[0, "b"] = 200 assert np.shares_memory(get_array(df, "a"), get_array(df2, "a")) df_orig = df.copy() - with tm.assert_cow_warning(warn_copy_on_write): - df2.loc[0, "a"] = 100 + df2.loc[0, "a"] = 100 if using_copy_on_write: # modifying child after deleting a column still doesn't update parent tm.assert_frame_equal(df, df_orig) @@ -929,7 +877,7 @@ def test_del_series(backend): # Accessing column as Series -def test_column_as_series(backend, using_copy_on_write, warn_copy_on_write): +def test_column_as_series(backend, using_copy_on_write): # Case: selecting a single column now also uses Copy-on-Write dtype_backend, DataFrame, Series = backend df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}) @@ -941,9 +889,6 @@ def test_column_as_series(backend, using_copy_on_write, warn_copy_on_write): if using_copy_on_write: s[0] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - s[0] = 0 else: warn = SettingWithCopyWarning if dtype_backend == "numpy" else None with pd.option_context("chained_assignment", "warn"): @@ -962,9 +907,7 @@ def test_column_as_series(backend, using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_column_as_series_set_with_upcast( - backend, using_copy_on_write, warn_copy_on_write -): +def test_column_as_series_set_with_upcast(backend, using_copy_on_write): # Case: selecting a single column now also uses Copy-on-Write -> when # setting a value causes an upcast, we don't need to update the parent # DataFrame through the cache mechanism @@ -974,12 +917,10 @@ def test_column_as_series_set_with_upcast( s = df["a"] if dtype_backend == "nullable": - with tm.assert_cow_warning(warn_copy_on_write): - with pytest.raises(TypeError, match="Invalid value"): - s[0] = "foo" + with pytest.raises(TypeError, match="Invalid value"): + s[0] = "foo" expected = Series([1, 2, 3], name="a") - elif using_copy_on_write or warn_copy_on_write: - # TODO(CoW-warn) assert the FutureWarning for CoW is also raised + elif using_copy_on_write: with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"): s[0] = "foo" expected = Series(["foo", 2, 3], dtype=object, name="a") @@ -1021,7 +962,6 @@ def test_column_as_series_no_item_cache( backend, method, using_copy_on_write, - warn_copy_on_write, ): # Case: selecting a single column (which now also uses Copy-on-Write to protect # the view) should always give a new object (i.e. not make use of a cache) @@ -1033,16 +973,13 @@ def test_column_as_series_no_item_cache( s2 = method(df) is_iloc = "iloc" in request.node.name - if using_copy_on_write or warn_copy_on_write or is_iloc: + if using_copy_on_write or is_iloc: assert s1 is not s2 else: assert s1 is s2 if using_copy_on_write: s1.iloc[0] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(): - s1.iloc[0] = 0 else: warn = SettingWithCopyWarning if dtype_backend == "numpy" else None with pd.option_context("chained_assignment", "warn"): @@ -1094,7 +1031,7 @@ def test_dataframe_add_column_from_series(backend, using_copy_on_write): "col", [[0.1, 0.2, 0.3], [7, 8, 9]], ids=["mixed-block", "single-block"] ) def test_set_value_copy_only_necessary_column( - using_copy_on_write, warn_copy_on_write, indexer_func, indexer, val, col + using_copy_on_write, indexer_func, indexer, val, col ): # When setting inplace, only copy column that is modified instead of the whole # block (by splitting the block) @@ -1102,19 +1039,13 @@ def test_set_value_copy_only_necessary_column( df_orig = df.copy() view = df[:] - if val == "a" and not warn_copy_on_write: + if val == "a": with tm.assert_produces_warning( FutureWarning, match="Setting an item of incompatible dtype is deprecated" ): indexer_func(df)[indexer] = val - if val == "a" and warn_copy_on_write: - with tm.assert_produces_warning( - FutureWarning, match="incompatible dtype|Setting a value on a view" - ): - indexer_func(df)[indexer] = val - else: - with tm.assert_cow_warning(warn_copy_on_write and val == 100): - indexer_func(df)[indexer] = val + + indexer_func(df)[indexer] = val if using_copy_on_write: assert np.shares_memory(get_array(df, "b"), get_array(view, "b")) @@ -1128,13 +1059,12 @@ def test_set_value_copy_only_necessary_column( assert np.shares_memory(get_array(df, "a"), get_array(view, "a")) -def test_series_midx_slice(using_copy_on_write, warn_copy_on_write): +def test_series_midx_slice(using_copy_on_write): ser = Series([1, 2, 3], index=pd.MultiIndex.from_arrays([[1, 1, 2], [3, 4, 5]])) ser_orig = ser.copy() result = ser[1] assert np.shares_memory(get_array(ser), get_array(result)) - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0] = 100 + result.iloc[0] = 100 if using_copy_on_write: tm.assert_series_equal(ser, ser_orig) else: @@ -1144,7 +1074,7 @@ def test_series_midx_slice(using_copy_on_write, warn_copy_on_write): tm.assert_series_equal(ser, expected) -def test_getitem_midx_slice(using_copy_on_write, warn_copy_on_write): +def test_getitem_midx_slice(using_copy_on_write): df = DataFrame({("a", "x"): [1, 2], ("a", "y"): 1, ("b", "x"): 2}) df_orig = df.copy() new_df = df[("a",)] @@ -1157,25 +1087,20 @@ def test_getitem_midx_slice(using_copy_on_write, warn_copy_on_write): new_df.iloc[0, 0] = 100 tm.assert_frame_equal(df_orig, df) else: - if warn_copy_on_write: - with tm.assert_cow_warning(): + with pd.option_context("chained_assignment", "warn"): + with tm.assert_produces_warning(SettingWithCopyWarning): new_df.iloc[0, 0] = 100 - else: - with pd.option_context("chained_assignment", "warn"): - with tm.assert_produces_warning(SettingWithCopyWarning): - new_df.iloc[0, 0] = 100 assert df.iloc[0, 0] == 100 -def test_series_midx_tuples_slice(using_copy_on_write, warn_copy_on_write): +def test_series_midx_tuples_slice(using_copy_on_write): ser = Series( [1, 2, 3], index=pd.MultiIndex.from_tuples([((1, 2), 3), ((1, 2), 4), ((2, 3), 4)]), ) result = ser[(1, 2)] assert np.shares_memory(get_array(ser), get_array(result)) - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0] = 100 + result.iloc[0] = 100 if using_copy_on_write: expected = Series( [1, 2, 3], diff --git a/pandas/tests/copy_view/test_interp_fillna.py b/pandas/tests/copy_view/test_interp_fillna.py index ddc5879a56d54..d72600956a6d6 100644 --- a/pandas/tests/copy_view/test_interp_fillna.py +++ b/pandas/tests/copy_view/test_interp_fillna.py @@ -10,7 +10,6 @@ Series, Timestamp, interval_range, - option_context, ) import pandas._testing as tm from pandas.tests.copy_view.util import get_array @@ -91,13 +90,12 @@ def test_interpolate_inplace_no_reference_no_copy(using_copy_on_write, vals): @pytest.mark.parametrize( "vals", [[1, np.nan, 2], [Timestamp("2019-12-31"), NaT, Timestamp("2020-12-31")]] ) -def test_interpolate_inplace_with_refs(using_copy_on_write, vals, warn_copy_on_write): +def test_interpolate_inplace_with_refs(using_copy_on_write, vals): df = DataFrame({"a": [1, np.nan, 2]}) df_orig = df.copy() arr = get_array(df, "a") view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.interpolate(method="linear", inplace=True) + df.interpolate(method="linear", inplace=True) if using_copy_on_write: # Check that copy was triggered in interpolate and that we don't @@ -112,17 +110,14 @@ def test_interpolate_inplace_with_refs(using_copy_on_write, vals, warn_copy_on_w @pytest.mark.parametrize("func", ["ffill", "bfill"]) @pytest.mark.parametrize("dtype", ["float64", "Float64"]) -def test_interp_fill_functions_inplace( - using_copy_on_write, func, warn_copy_on_write, dtype -): +def test_interp_fill_functions_inplace(using_copy_on_write, func, dtype): # Check that these takes the same code paths as interpolate df = DataFrame({"a": [1, np.nan, 2]}, dtype=dtype) df_orig = df.copy() arr = get_array(df, "a") view = df[:] - with tm.assert_cow_warning(warn_copy_on_write and dtype == "float64"): - getattr(df, func)(inplace=True) + getattr(df, func)(inplace=True) if using_copy_on_write: # Check that copy was triggered in interpolate and that we don't @@ -255,15 +250,14 @@ def test_fillna_inplace(using_copy_on_write, downcast): assert df._mgr._has_no_reference(1) -def test_fillna_inplace_reference(using_copy_on_write, warn_copy_on_write): +def test_fillna_inplace_reference(using_copy_on_write): df = DataFrame({"a": [1.5, np.nan], "b": 1}) df_orig = df.copy() arr_a = get_array(df, "a") arr_b = get_array(df, "b") view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.fillna(5.5, inplace=True) + df.fillna(5.5, inplace=True) if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), arr_a) assert np.shares_memory(get_array(df, "b"), arr_b) @@ -277,7 +271,7 @@ def test_fillna_inplace_reference(using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(df, expected) -def test_fillna_interval_inplace_reference(using_copy_on_write, warn_copy_on_write): +def test_fillna_interval_inplace_reference(using_copy_on_write): # Set dtype explicitly to avoid implicit cast when setting nan ser = Series( interval_range(start=0, end=5), name="a", dtype="interval[float64, right]" @@ -286,8 +280,7 @@ def test_fillna_interval_inplace_reference(using_copy_on_write, warn_copy_on_wri ser_orig = ser.copy() view = ser[:] - with tm.assert_cow_warning(warn_copy_on_write): - ser.fillna(value=Interval(left=0, right=5), inplace=True) + ser.fillna(value=Interval(left=0, right=5), inplace=True) if using_copy_on_write: assert not np.shares_memory( @@ -353,13 +346,12 @@ def test_fillna_ea_noop_shares_memory( def test_fillna_inplace_ea_noop_shares_memory( - using_copy_on_write, warn_copy_on_write, any_numeric_ea_and_arrow_dtype + using_copy_on_write, any_numeric_ea_and_arrow_dtype ): df = DataFrame({"a": [1, NA, 3], "b": 1}, dtype=any_numeric_ea_and_arrow_dtype) df_orig = df.copy() view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.fillna(100, inplace=True) + df.fillna(100, inplace=True) if isinstance(df["a"].dtype, ArrowDtype) or using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), get_array(view, "a")) @@ -372,10 +364,7 @@ def test_fillna_inplace_ea_noop_shares_memory( assert not df._mgr._has_no_reference(1) assert not view._mgr._has_no_reference(1) - with tm.assert_cow_warning( - warn_copy_on_write and "pyarrow" not in any_numeric_ea_and_arrow_dtype - ): - df.iloc[0, 1] = 100 + df.iloc[0, 1] = 100 if isinstance(df["a"].dtype, ArrowDtype) or using_copy_on_write: tm.assert_frame_equal(df_orig, view) else: @@ -383,50 +372,26 @@ def test_fillna_inplace_ea_noop_shares_memory( tm.assert_frame_equal(df, view) -def test_fillna_chained_assignment(using_copy_on_write): +def test_fillna_chained_assignment(): df = DataFrame({"a": [1, np.nan, 2], "b": 1}) df_orig = df.copy() - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - df["a"].fillna(100, inplace=True) - tm.assert_frame_equal(df, df_orig) - - with tm.raises_chained_assignment_error(): - df[["a"]].fillna(100, inplace=True) - tm.assert_frame_equal(df, df_orig) - else: - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[["a"]].fillna(100, inplace=True) - - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[df.a > 5].fillna(100, inplace=True) + with tm.raises_chained_assignment_error(): + df["a"].fillna(100, inplace=True) + tm.assert_frame_equal(df, df_orig) - with tm.assert_produces_warning(FutureWarning, match="inplace method"): - df["a"].fillna(100, inplace=True) + with tm.raises_chained_assignment_error(): + df[["a"]].fillna(100, inplace=True) + tm.assert_frame_equal(df, df_orig) @pytest.mark.parametrize("func", ["interpolate", "ffill", "bfill"]) -def test_interpolate_chained_assignment(using_copy_on_write, func): +def test_interpolate_chained_assignment(func): df = DataFrame({"a": [1, np.nan, 2], "b": 1}) df_orig = df.copy() - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - getattr(df["a"], func)(inplace=True) - tm.assert_frame_equal(df, df_orig) - - with tm.raises_chained_assignment_error(): - getattr(df[["a"]], func)(inplace=True) - tm.assert_frame_equal(df, df_orig) - else: - with tm.assert_produces_warning(FutureWarning, match="inplace method"): - getattr(df["a"], func)(inplace=True) - - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - getattr(df[["a"]], func)(inplace=True) + with tm.raises_chained_assignment_error(): + getattr(df["a"], func)(inplace=True) + tm.assert_frame_equal(df, df_orig) - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - getattr(df[df["a"] > 1], func)(inplace=True) + with tm.raises_chained_assignment_error(): + getattr(df[["a"]], func)(inplace=True) + tm.assert_frame_equal(df, df_orig) diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py index 590829b6dc759..b3bd63e1c7e4c 100644 --- a/pandas/tests/copy_view/test_methods.py +++ b/pandas/tests/copy_view/test_methods.py @@ -40,7 +40,7 @@ def test_copy(using_copy_on_write): assert df.iloc[0, 0] == 1 -def test_copy_shallow(using_copy_on_write, warn_copy_on_write): +def test_copy_shallow(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}) df_copy = df.copy(deep=False) @@ -70,8 +70,7 @@ def test_copy_shallow(using_copy_on_write, warn_copy_on_write): assert np.shares_memory(get_array(df_copy, "c"), get_array(df, "c")) else: # mutating shallow copy does mutate original - with tm.assert_cow_warning(warn_copy_on_write): - df_copy.iloc[0, 0] = 0 + df_copy.iloc[0, 0] = 0 assert df.iloc[0, 0] == 0 # and still shares memory assert np.shares_memory(get_array(df_copy, "a"), get_array(df, "a")) @@ -525,15 +524,14 @@ def test_shift_rows_freq(using_copy_on_write): tm.assert_frame_equal(df2, df_orig) -def test_shift_columns(using_copy_on_write, warn_copy_on_write): +def test_shift_columns(using_copy_on_write): df = DataFrame( [[1, 2], [3, 4], [5, 6]], columns=date_range("2020-01-01", "2020-01-02") ) df2 = df.shift(periods=1, axis=1) assert np.shares_memory(get_array(df2, "2020-01-02"), get_array(df, "2020-01-01")) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 if using_copy_on_write: assert not np.shares_memory( get_array(df2, "2020-01-02"), get_array(df, "2020-01-01") @@ -545,7 +543,7 @@ def test_shift_columns(using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(df2, expected) -def test_pop(using_copy_on_write, warn_copy_on_write): +def test_pop(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}) df_orig = df.copy() view_original = df[:] @@ -557,8 +555,7 @@ def test_pop(using_copy_on_write, warn_copy_on_write): if using_copy_on_write: result.iloc[0] = 0 assert not np.shares_memory(result.values, get_array(view_original, "a")) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(df, "b"), get_array(view_original, "b")) tm.assert_frame_equal(view_original, df_orig) @@ -649,7 +646,7 @@ def test_align_with_series_copy_false(using_copy_on_write): tm.assert_series_equal(ser, ser_orig) # Original is unchanged -def test_to_frame(using_copy_on_write, warn_copy_on_write): +def test_to_frame(using_copy_on_write): # Case: converting a Series to a DataFrame with to_frame ser = Series([1, 2, 3]) ser_orig = ser.copy() @@ -659,8 +656,7 @@ def test_to_frame(using_copy_on_write, warn_copy_on_write): # currently this always returns a "view" assert np.shares_memory(ser.values, get_array(df, 0)) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 if using_copy_on_write: # mutating df triggers a copy-on-write for that column @@ -674,8 +670,7 @@ def test_to_frame(using_copy_on_write, warn_copy_on_write): # modify original series -> don't modify dataframe df = ser[:].to_frame() - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 0 + ser.iloc[0] = 0 if using_copy_on_write: tm.assert_frame_equal(df, ser_orig.to_frame()) @@ -744,7 +739,7 @@ def test_swapaxes_read_only_array(): ], ids=["shallow-copy", "reset_index", "rename", "select_dtypes"], ) -def test_chained_methods(request, method, idx, using_copy_on_write, warn_copy_on_write): +def test_chained_methods(request, method, idx, using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [0.1, 0.2, 0.3]}) df_orig = df.copy() @@ -753,15 +748,13 @@ def test_chained_methods(request, method, idx, using_copy_on_write, warn_copy_on # modify df2 -> don't modify df df2 = method(df) - with tm.assert_cow_warning(warn_copy_on_write and df2_is_view): - df2.iloc[0, idx] = 0 + df2.iloc[0, idx] = 0 if not df2_is_view: tm.assert_frame_equal(df, df_orig) # modify df -> don't modify df2 df2 = method(df) - with tm.assert_cow_warning(warn_copy_on_write and df2_is_view): - df.iloc[0, 0] = 0 + df.iloc[0, 0] = 0 if not df2_is_view: tm.assert_frame_equal(df2.iloc[:, idx:], df_orig) @@ -910,7 +903,7 @@ def test_dropna_series(using_copy_on_write, val): lambda df: df.tail(3), ], ) -def test_head_tail(method, using_copy_on_write, warn_copy_on_write): +def test_head_tail(method, using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [0.1, 0.2, 0.3]}) df_orig = df.copy() df2 = method(df) @@ -923,16 +916,14 @@ def test_head_tail(method, using_copy_on_write, warn_copy_on_write): assert not np.shares_memory(get_array(df2, "b"), get_array(df, "b")) # modify df2 to trigger CoW for that block - with tm.assert_cow_warning(warn_copy_on_write): - df2.iloc[0, 0] = 0 + df2.iloc[0, 0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(df2, "b"), get_array(df, "b")) assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) else: # without CoW enabled, head and tail return views. Mutating df2 also mutates df. assert np.shares_memory(get_array(df2, "b"), get_array(df, "b")) - with tm.assert_cow_warning(warn_copy_on_write): - df2.iloc[0, 0] = 1 + df2.iloc[0, 0] = 1 tm.assert_frame_equal(df, df_orig) @@ -1146,7 +1137,7 @@ def test_sort_values(using_copy_on_write, obj, kwargs): "obj, kwargs", [(Series([1, 2, 3], name="a"), {}), (DataFrame({"a": [1, 2, 3]}), {"by": "a"})], ) -def test_sort_values_inplace(using_copy_on_write, obj, kwargs, warn_copy_on_write): +def test_sort_values_inplace(using_copy_on_write, obj, kwargs): obj_orig = obj.copy() view = obj[:] obj.sort_values(inplace=True, **kwargs) @@ -1154,8 +1145,7 @@ def test_sort_values_inplace(using_copy_on_write, obj, kwargs, warn_copy_on_writ assert np.shares_memory(get_array(obj, "a"), get_array(view, "a")) # mutating obj triggers a copy-on-write for the column / block - with tm.assert_cow_warning(warn_copy_on_write): - obj.iloc[0] = 0 + obj.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(obj, "a"), get_array(view, "a")) tm.assert_equal(view, obj_orig) @@ -1164,7 +1154,7 @@ def test_sort_values_inplace(using_copy_on_write, obj, kwargs, warn_copy_on_writ @pytest.mark.parametrize("decimals", [-1, 0, 1]) -def test_round(using_copy_on_write, warn_copy_on_write, decimals): +def test_round(using_copy_on_write, decimals): df = DataFrame({"a": [1, 2], "b": "c"}) df_orig = df.copy() df2 = df.round(decimals=decimals) @@ -1279,7 +1269,7 @@ def test_series_set_axis(using_copy_on_write): tm.assert_series_equal(ser, ser_orig) -def test_set_flags(using_copy_on_write, warn_copy_on_write): +def test_set_flags(using_copy_on_write): ser = Series([1, 2, 3]) ser_orig = ser.copy() ser2 = ser.set_flags(allows_duplicate_labels=False) @@ -1287,8 +1277,7 @@ def test_set_flags(using_copy_on_write, warn_copy_on_write): assert np.shares_memory(ser, ser2) # mutating ser triggers a copy-on-write for the column / block - with tm.assert_cow_warning(warn_copy_on_write): - ser2.iloc[0] = 0 + ser2.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(ser2, ser) tm.assert_series_equal(ser, ser_orig) @@ -1361,7 +1350,7 @@ def test_droplevel(using_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_squeeze(using_copy_on_write, warn_copy_on_write): +def test_squeeze(using_copy_on_write): df = DataFrame({"a": [1, 2, 3]}) df_orig = df.copy() series = df.squeeze() @@ -1370,8 +1359,7 @@ def test_squeeze(using_copy_on_write, warn_copy_on_write): assert np.shares_memory(series.values, get_array(df, "a")) # mutating squeezed df triggers a copy-on-write for that column/block - with tm.assert_cow_warning(warn_copy_on_write): - series.iloc[0] = 0 + series.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(series.values, get_array(df, "a")) tm.assert_frame_equal(df, df_orig) @@ -1381,7 +1369,7 @@ def test_squeeze(using_copy_on_write, warn_copy_on_write): assert df.loc[0, "a"] == 0 -def test_items(using_copy_on_write, warn_copy_on_write): +def test_items(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) df_orig = df.copy() @@ -1392,8 +1380,7 @@ def test_items(using_copy_on_write, warn_copy_on_write): assert np.shares_memory(get_array(ser, name), get_array(df, name)) # mutating df triggers a copy-on-write for that column / block - with tm.assert_cow_warning(warn_copy_on_write): - ser.iloc[0] = 0 + ser.iloc[0] = 0 if using_copy_on_write: assert not np.shares_memory(get_array(ser, name), get_array(df, name)) @@ -1404,12 +1391,11 @@ def test_items(using_copy_on_write, warn_copy_on_write): @pytest.mark.parametrize("dtype", ["int64", "Int64"]) -def test_putmask(using_copy_on_write, dtype, warn_copy_on_write): +def test_putmask(using_copy_on_write, dtype): df = DataFrame({"a": [1, 2], "b": 1, "c": 2}, dtype=dtype) view = df[:] df_orig = df.copy() - with tm.assert_cow_warning(warn_copy_on_write): - df[df == df] = 5 + df[df == df] = 5 if using_copy_on_write: assert not np.shares_memory(get_array(view, "a"), get_array(df, "a")) @@ -1443,21 +1429,15 @@ def test_putmask_aligns_rhs_no_reference(using_copy_on_write, dtype): @pytest.mark.parametrize( "val, exp, warn", [(5.5, True, FutureWarning), (5, False, None)] ) -def test_putmask_dont_copy_some_blocks( - using_copy_on_write, val, exp, warn, warn_copy_on_write -): +def test_putmask_dont_copy_some_blocks(using_copy_on_write, val, exp, warn): df = DataFrame({"a": [1, 2], "b": 1, "c": 1.5}) view = df[:] df_orig = df.copy() indexer = DataFrame( [[True, False, False], [True, False, False]], columns=list("abc") ) - if warn_copy_on_write: - with tm.assert_cow_warning(): - df[indexer] = val - else: - with tm.assert_produces_warning(warn, match="incompatible dtype"): - df[indexer] = val + with tm.assert_produces_warning(warn, match="incompatible dtype"): + df[indexer] = val if using_copy_on_write: assert not np.shares_memory(get_array(view, "a"), get_array(df, "a")) @@ -1598,16 +1578,14 @@ def test_iterrows(using_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_interpolate_creates_copy(using_copy_on_write, warn_copy_on_write): +def test_interpolate_creates_copy(using_copy_on_write): # GH#51126 df = DataFrame({"a": [1.5, np.nan, 3]}) view = df[:] expected = df.copy() - with tm.assert_cow_warning(warn_copy_on_write): - df.ffill(inplace=True) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100.5 + df.ffill(inplace=True) + df.iloc[0, 0] = 100.5 if using_copy_on_write: tm.assert_frame_equal(view, expected) @@ -1683,7 +1661,7 @@ def test_isetitem_frame(using_copy_on_write): @pytest.mark.parametrize("key", ["a", ["a"]]) -def test_get(using_copy_on_write, warn_copy_on_write, key): +def test_get(using_copy_on_write, key): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) df_orig = df.copy() @@ -1697,10 +1675,7 @@ def test_get(using_copy_on_write, warn_copy_on_write, key): else: # for non-CoW it depends on whether we got a Series or DataFrame if it # is a view or copy or triggers a warning or not - if warn_copy_on_write: - warn = FutureWarning if isinstance(key, str) else None - else: - warn = SettingWithCopyWarning if isinstance(key, list) else None + warn = SettingWithCopyWarning if isinstance(key, list) else None with option_context("chained_assignment", "warn"): with tm.assert_produces_warning(warn): result.iloc[0] = 0 @@ -1715,7 +1690,7 @@ def test_get(using_copy_on_write, warn_copy_on_write, key): @pytest.mark.parametrize( "dtype", ["int64", "float64"], ids=["single-block", "mixed-block"] ) -def test_xs(using_copy_on_write, warn_copy_on_write, axis, key, dtype): +def test_xs(using_copy_on_write, axis, key, dtype): single_block = dtype == "int64" df = DataFrame( {"a": [1, 2, 3], "b": [4, 5, 6], "c": np.array([7, 8, 9], dtype=dtype)} @@ -1729,11 +1704,8 @@ def test_xs(using_copy_on_write, warn_copy_on_write, axis, key, dtype): elif using_copy_on_write: assert result._mgr._has_no_reference(0) - if using_copy_on_write or (single_block and not warn_copy_on_write): + if using_copy_on_write or single_block: result.iloc[0] = 0 - elif warn_copy_on_write: - with tm.assert_cow_warning(single_block or axis == 1): - result.iloc[0] = 0 else: with option_context("chained_assignment", "warn"): with tm.assert_produces_warning(SettingWithCopyWarning): @@ -1747,7 +1719,7 @@ def test_xs(using_copy_on_write, warn_copy_on_write, axis, key, dtype): @pytest.mark.parametrize("axis", [0, 1]) @pytest.mark.parametrize("key, level", [("l1", 0), (2, 1)]) -def test_xs_multiindex(using_copy_on_write, warn_copy_on_write, key, level, axis): +def test_xs_multiindex(using_copy_on_write, key, level, axis): arr = np.arange(18).reshape(6, 3) index = MultiIndex.from_product([["l1", "l2"], [1, 2, 3]], names=["lev1", "lev2"]) df = DataFrame(arr, index=index, columns=list("abc")) @@ -1762,9 +1734,7 @@ def test_xs_multiindex(using_copy_on_write, warn_copy_on_write, key, level, axis get_array(df, df.columns[0]), get_array(result, result.columns[0]) ) - if warn_copy_on_write: - warn = FutureWarning if level == 0 else None - elif not using_copy_on_write: + if not using_copy_on_write: warn = SettingWithCopyWarning else: warn = None @@ -1775,15 +1745,12 @@ def test_xs_multiindex(using_copy_on_write, warn_copy_on_write, key, level, axis tm.assert_frame_equal(df, df_orig) -def test_update_frame(using_copy_on_write, warn_copy_on_write): +def test_update_frame(using_copy_on_write): df1 = DataFrame({"a": [1.0, 2.0, 3.0], "b": [4.0, 5.0, 6.0]}) df2 = DataFrame({"b": [100.0]}, index=[1]) df1_orig = df1.copy() view = df1[:] - - # TODO(CoW) better warning message? - with tm.assert_cow_warning(warn_copy_on_write): - df1.update(df2) + df1.update(df2) expected = DataFrame({"a": [1.0, 2.0, 3.0], "b": [4.0, 100.0, 6.0]}) tm.assert_frame_equal(df1, expected) @@ -1796,17 +1763,13 @@ def test_update_frame(using_copy_on_write, warn_copy_on_write): tm.assert_frame_equal(view, expected) -def test_update_series(using_copy_on_write, warn_copy_on_write): +def test_update_series(using_copy_on_write): ser1 = Series([1.0, 2.0, 3.0]) ser2 = Series([100.0], index=[1]) ser1_orig = ser1.copy() view = ser1[:] - if warn_copy_on_write: - with tm.assert_cow_warning(): - ser1.update(ser2) - else: - ser1.update(ser2) + ser1.update(ser2) expected = Series([1.0, 100.0, 3.0]) tm.assert_series_equal(ser1, expected) @@ -1817,29 +1780,17 @@ def test_update_series(using_copy_on_write, warn_copy_on_write): tm.assert_series_equal(view, expected) -def test_update_chained_assignment(using_copy_on_write): +def test_update_chained_assignment(): df = DataFrame({"a": [1, 2, 3]}) ser2 = Series([100.0], index=[1]) df_orig = df.copy() - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - df["a"].update(ser2) - tm.assert_frame_equal(df, df_orig) - - with tm.raises_chained_assignment_error(): - df[["a"]].update(ser2.to_frame()) - tm.assert_frame_equal(df, df_orig) - else: - with tm.assert_produces_warning(FutureWarning, match="inplace method"): - df["a"].update(ser2) - - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[["a"]].update(ser2.to_frame()) + with tm.raises_chained_assignment_error(): + df["a"].update(ser2) + tm.assert_frame_equal(df, df_orig) - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[df["a"] > 1].update(ser2.to_frame()) + with tm.raises_chained_assignment_error(): + df[["a"]].update(ser2.to_frame()) + tm.assert_frame_equal(df, df_orig) def test_inplace_arithmetic_series(using_copy_on_write): @@ -1860,14 +1811,11 @@ def test_inplace_arithmetic_series(using_copy_on_write): tm.assert_numpy_array_equal(data, get_array(ser)) -def test_inplace_arithmetic_series_with_reference( - using_copy_on_write, warn_copy_on_write -): +def test_inplace_arithmetic_series_with_reference(using_copy_on_write): ser = Series([1, 2, 3]) ser_orig = ser.copy() view = ser[:] - with tm.assert_cow_warning(warn_copy_on_write): - ser *= 2 + ser *= 2 if using_copy_on_write: assert not np.shares_memory(get_array(ser), get_array(view)) tm.assert_series_equal(ser_orig, view) @@ -1909,7 +1857,7 @@ def test_transpose_ea_single_column(using_copy_on_write): assert not np.shares_memory(get_array(df, "a"), get_array(result, 0)) -def test_transform_frame(using_copy_on_write, warn_copy_on_write): +def test_transform_frame(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": 1}) df_orig = df.copy() @@ -1917,13 +1865,12 @@ def func(ser): ser.iloc[0] = 100 return ser - with tm.assert_cow_warning(warn_copy_on_write): - df.transform(func) + df.transform(func) if using_copy_on_write: tm.assert_frame_equal(df, df_orig) -def test_transform_series(using_copy_on_write, warn_copy_on_write): +def test_transform_series(using_copy_on_write): ser = Series([1, 2, 3]) ser_orig = ser.copy() @@ -1931,8 +1878,7 @@ def func(ser): ser.iloc[0] = 100 return ser - with tm.assert_cow_warning(warn_copy_on_write): - ser.transform(func) + ser.transform(func) if using_copy_on_write: tm.assert_series_equal(ser, ser_orig) @@ -1945,7 +1891,7 @@ def test_count_read_only_array(): tm.assert_series_equal(result, expected) -def test_series_view(using_copy_on_write, warn_copy_on_write): +def test_series_view(using_copy_on_write): ser = Series([1, 2, 3]) ser_orig = ser.copy() @@ -1955,8 +1901,7 @@ def test_series_view(using_copy_on_write, warn_copy_on_write): if using_copy_on_write: assert not ser2._mgr._has_no_reference(0) - with tm.assert_cow_warning(warn_copy_on_write): - ser2.iloc[0] = 100 + ser2.iloc[0] = 100 if using_copy_on_write: tm.assert_series_equal(ser_orig, ser) @@ -1994,7 +1939,7 @@ def test_eval(using_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_eval_inplace(using_copy_on_write, warn_copy_on_write): +def test_eval_inplace(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": 1}) df_orig = df.copy() df_view = df[:] @@ -2002,13 +1947,12 @@ def test_eval_inplace(using_copy_on_write, warn_copy_on_write): df.eval("c = a+b", inplace=True) assert np.shares_memory(get_array(df, "a"), get_array(df_view, "a")) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100 + df.iloc[0, 0] = 100 if using_copy_on_write: tm.assert_frame_equal(df_view, df_orig) -def test_apply_modify_row(using_copy_on_write, warn_copy_on_write): +def test_apply_modify_row(using_copy_on_write): # Case: applying a function on each row as a Series object, where the # function mutates the row object (which needs to trigger CoW if row is a view) df = DataFrame({"A": [1, 2], "B": [3, 4]}) @@ -2018,8 +1962,7 @@ def transform(row): row["B"] = 100 return row - with tm.assert_cow_warning(warn_copy_on_write): - df.apply(transform, axis=1) + df.apply(transform, axis=1) if using_copy_on_write: tm.assert_frame_equal(df, df_orig) diff --git a/pandas/tests/copy_view/test_replace.py b/pandas/tests/copy_view/test_replace.py index 1a0a77b332743..f2ee26c0b9009 100644 --- a/pandas/tests/copy_view/test_replace.py +++ b/pandas/tests/copy_view/test_replace.py @@ -4,7 +4,6 @@ from pandas import ( Categorical, DataFrame, - option_context, ) import pandas._testing as tm from pandas.tests.copy_view.util import get_array @@ -48,13 +47,12 @@ def test_replace(using_copy_on_write, replace_kwargs): tm.assert_frame_equal(df, df_orig) -def test_replace_regex_inplace_refs(using_copy_on_write, warn_copy_on_write): +def test_replace_regex_inplace_refs(using_copy_on_write): df = DataFrame({"a": ["aaa", "bbb"]}) df_orig = df.copy() view = df[:] arr = get_array(df, "a") - with tm.assert_cow_warning(warn_copy_on_write): - df.replace(to_replace=r"^a.*$", value="new", inplace=True, regex=True) + df.replace(to_replace=r"^a.*$", value="new", inplace=True, regex=True) if using_copy_on_write: assert not np.shares_memory(arr, get_array(df, "a")) assert df._mgr._has_no_reference(0) @@ -214,12 +212,11 @@ def test_replace_inplace(using_copy_on_write, to_replace): @pytest.mark.parametrize("to_replace", [1.5, [1.5]]) -def test_replace_inplace_reference(using_copy_on_write, to_replace, warn_copy_on_write): +def test_replace_inplace_reference(using_copy_on_write, to_replace): df = DataFrame({"a": [1.5, 2, 3]}) arr_a = get_array(df, "a") view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.replace(to_replace=to_replace, value=15.5, inplace=True) + df.replace(to_replace=to_replace, value=15.5, inplace=True) if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), arr_a) @@ -310,18 +307,14 @@ def test_replace_categorical(using_copy_on_write, val): @pytest.mark.parametrize("method", ["where", "mask"]) -def test_masking_inplace(using_copy_on_write, method, warn_copy_on_write): +def test_masking_inplace(using_copy_on_write, method): df = DataFrame({"a": [1.5, 2, 3]}) df_orig = df.copy() arr_a = get_array(df, "a") view = df[:] method = getattr(df, method) - if warn_copy_on_write: - with tm.assert_cow_warning(): - method(df["a"] > 1.6, -1, inplace=True) - else: - method(df["a"] > 1.6, -1, inplace=True) + method(df["a"] > 1.6, -1, inplace=True) if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), arr_a) @@ -385,13 +378,12 @@ def test_replace_list_none(using_copy_on_write): assert not np.shares_memory(get_array(df, "a"), get_array(df2, "a")) -def test_replace_list_none_inplace_refs(using_copy_on_write, warn_copy_on_write): +def test_replace_list_none_inplace_refs(using_copy_on_write): df = DataFrame({"a": ["a", "b", "c"]}) arr = get_array(df, "a") df_orig = df.copy() view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.replace(["a"], value=None, inplace=True) + df.replace(["a"], value=None, inplace=True) if using_copy_on_write: assert df._mgr._has_no_reference(0) assert not np.shares_memory(arr, get_array(df, "a")) @@ -421,28 +413,16 @@ def test_replace_columnwise_no_op(using_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_replace_chained_assignment(using_copy_on_write): +def test_replace_chained_assignment(): df = DataFrame({"a": [1, np.nan, 2], "b": 1}) df_orig = df.copy() - if using_copy_on_write: - with tm.raises_chained_assignment_error(): - df["a"].replace(1, 100, inplace=True) - tm.assert_frame_equal(df, df_orig) - - with tm.raises_chained_assignment_error(): - df[["a"]].replace(1, 100, inplace=True) - tm.assert_frame_equal(df, df_orig) - else: - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[["a"]].replace(1, 100, inplace=True) - - with tm.assert_produces_warning(None): - with option_context("mode.chained_assignment", None): - df[df.a > 5].replace(1, 100, inplace=True) + with tm.raises_chained_assignment_error(): + df["a"].replace(1, 100, inplace=True) + tm.assert_frame_equal(df, df_orig) - with tm.assert_produces_warning(FutureWarning, match="inplace method"): - df["a"].replace(1, 100, inplace=True) + with tm.raises_chained_assignment_error(): + df[["a"]].replace(1, 100, inplace=True) + tm.assert_frame_equal(df, df_orig) def test_replace_listlike(using_copy_on_write): @@ -463,7 +443,7 @@ def test_replace_listlike(using_copy_on_write): tm.assert_frame_equal(df, df_orig) -def test_replace_listlike_inplace(using_copy_on_write, warn_copy_on_write): +def test_replace_listlike_inplace(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [1, 2, 3]}) arr = get_array(df, "a") df.replace([200, 2], [10, 11], inplace=True) @@ -471,8 +451,7 @@ def test_replace_listlike_inplace(using_copy_on_write, warn_copy_on_write): view = df[:] df_orig = df.copy() - with tm.assert_cow_warning(warn_copy_on_write): - df.replace([200, 3], [10, 11], inplace=True) + df.replace([200, 3], [10, 11], inplace=True) if using_copy_on_write: assert not np.shares_memory(get_array(df, "a"), arr) tm.assert_frame_equal(view, df_orig) diff --git a/pandas/tests/copy_view/test_setitem.py b/pandas/tests/copy_view/test_setitem.py index bc3b939734534..6104699cbc51b 100644 --- a/pandas/tests/copy_view/test_setitem.py +++ b/pandas/tests/copy_view/test_setitem.py @@ -142,7 +142,7 @@ def test_setitem_series_column_midx_broadcasting(using_copy_on_write): assert df._mgr._has_no_reference(0) -def test_set_column_with_inplace_operator(using_copy_on_write, warn_copy_on_write): +def test_set_column_with_inplace_operator(using_copy_on_write): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) # this should not raise any warning @@ -152,5 +152,4 @@ def test_set_column_with_inplace_operator(using_copy_on_write, warn_copy_on_writ # when it is not in a chain, then it should produce a warning df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) ser = df["a"] - with tm.assert_cow_warning(warn_copy_on_write): - ser += 1 + ser += 1 diff --git a/pandas/tests/frame/indexing/test_getitem.py b/pandas/tests/frame/indexing/test_getitem.py index a36b0c0e850b3..73683922bcc92 100644 --- a/pandas/tests/frame/indexing/test_getitem.py +++ b/pandas/tests/frame/indexing/test_getitem.py @@ -392,14 +392,13 @@ def test_getitem_empty_frame_with_boolean(self): tm.assert_frame_equal(df, df2) def test_getitem_returns_view_when_column_is_unique_in_df( - self, using_copy_on_write, warn_copy_on_write + self, using_copy_on_write ): # GH#45316 df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=["a", "a", "b"]) df_orig = df.copy() view = df["b"] - with tm.assert_cow_warning(warn_copy_on_write): - view.loc[:] = 100 + view.loc[:] = 100 if using_copy_on_write: expected = df_orig else: diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 0373c15d15272..c8787ac0b364e 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -287,9 +287,7 @@ def test_setattr_column(self): df.foobar = 5 assert (df.foobar == 5).all() - def test_setitem( - self, float_frame, using_copy_on_write, warn_copy_on_write, using_infer_string - ): + def test_setitem(self, float_frame, using_copy_on_write, using_infer_string): # not sure what else to do here series = float_frame["A"][::2] float_frame["col5"] = series @@ -325,7 +323,7 @@ def test_setitem( smaller = float_frame[:2] msg = r"\nA value is trying to be set on a copy of a slice from a DataFrame" - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: # With CoW, adding a new column doesn't raise a warning smaller["col10"] = ["1", "2"] else: @@ -574,7 +572,7 @@ def test_getitem_setitem_integer_slice_keyerrors(self): df2.loc[3:11] = 0 def test_fancy_getitem_slice_mixed( - self, float_frame, float_string_frame, using_copy_on_write, warn_copy_on_write + self, float_frame, float_string_frame, using_copy_on_write ): sliced = float_string_frame.iloc[:, -3:] assert sliced["D"].dtype == np.float64 @@ -586,8 +584,7 @@ def test_fancy_getitem_slice_mixed( assert np.shares_memory(sliced["C"]._values, float_frame["C"]._values) - with tm.assert_cow_warning(warn_copy_on_write): - sliced.loc[:, "C"] = 4.0 + sliced.loc[:, "C"] = 4.0 if not using_copy_on_write: assert (float_frame["C"] == 4).all() @@ -1062,7 +1059,7 @@ def test_iloc_row(self): expected = df.reindex(df.index[[1, 2, 4, 6]]) tm.assert_frame_equal(result, expected) - def test_iloc_row_slice_view(self, using_copy_on_write, warn_copy_on_write): + def test_iloc_row_slice_view(self, using_copy_on_write): df = DataFrame( np.random.default_rng(2).standard_normal((10, 4)), index=range(0, 20, 2) ) @@ -1075,8 +1072,7 @@ def test_iloc_row_slice_view(self, using_copy_on_write, warn_copy_on_write): assert np.shares_memory(df[2], subset[2]) exp_col = original[2].copy() - with tm.assert_cow_warning(warn_copy_on_write): - subset.loc[:, 2] = 0.0 + subset.loc[:, 2] = 0.0 if not using_copy_on_write: exp_col._values[4:8] = 0.0 @@ -1107,7 +1103,7 @@ def test_iloc_col(self): expected = df.reindex(columns=df.columns[[1, 2, 4, 6]]) tm.assert_frame_equal(result, expected) - def test_iloc_col_slice_view(self, using_copy_on_write, warn_copy_on_write): + def test_iloc_col_slice_view(self, using_copy_on_write): df = DataFrame( np.random.default_rng(2).standard_normal((4, 10)), columns=range(0, 20, 2) ) @@ -1118,8 +1114,7 @@ def test_iloc_col_slice_view(self, using_copy_on_write, warn_copy_on_write): # verify slice is view assert np.shares_memory(df[8]._values, subset[8]._values) - with tm.assert_cow_warning(warn_copy_on_write): - subset.loc[:, 8] = 0.0 + subset.loc[:, 8] = 0.0 assert (df[8] == 0).all() @@ -1401,7 +1396,7 @@ def test_loc_setitem_rhs_frame(self, idxr, val): expected = DataFrame({"a": [np.nan, val]}) tm.assert_frame_equal(df, expected) - def test_iloc_setitem_enlarge_no_warning(self, warn_copy_on_write): + def test_iloc_setitem_enlarge_no_warning(self): # GH#47381 df = DataFrame(columns=["a", "b"]) expected = df.copy() diff --git a/pandas/tests/frame/indexing/test_setitem.py b/pandas/tests/frame/indexing/test_setitem.py index 72cd98ba78122..2df01b2cdb721 100644 --- a/pandas/tests/frame/indexing/test_setitem.py +++ b/pandas/tests/frame/indexing/test_setitem.py @@ -844,7 +844,7 @@ def test_setitem_object_array_of_tzaware_datetimes(self, idx, expected): class TestDataFrameSetItemWithExpansion: - def test_setitem_listlike_views(self, using_copy_on_write, warn_copy_on_write): + def test_setitem_listlike_views(self, using_copy_on_write): # GH#38148 df = DataFrame({"a": [1, 2, 3], "b": [4, 4, 6]}) @@ -855,8 +855,7 @@ def test_setitem_listlike_views(self, using_copy_on_write, warn_copy_on_write): df[["c", "d"]] = np.array([[0.1, 0.2], [0.3, 0.4], [0.4, 0.5]]) # edit in place the first column to check view semantics - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 100 + df.iloc[0, 0] = 100 if using_copy_on_write: expected = Series([1, 2, 3], name="a") @@ -1299,9 +1298,7 @@ def test_setitem_not_operating_inplace(self, value, set_value, indexer): df[indexer] = set_value tm.assert_frame_equal(view, expected) - def test_setitem_column_update_inplace( - self, using_copy_on_write, warn_copy_on_write - ): + def test_setitem_column_update_inplace(self, using_copy_on_write): # https://github.com/pandas-dev/pandas/issues/47172 labels = [f"c{i}" for i in range(10)] diff --git a/pandas/tests/frame/indexing/test_xs.py b/pandas/tests/frame/indexing/test_xs.py index 80b4635b94d3b..dc2f0b61e3ba0 100644 --- a/pandas/tests/frame/indexing/test_xs.py +++ b/pandas/tests/frame/indexing/test_xs.py @@ -60,7 +60,7 @@ def test_xs_dt_error(self, datetime_frame): ): datetime_frame.xs(datetime_frame.index[0] - BDay()) - def test_xs_other(self, float_frame, using_copy_on_write, warn_copy_on_write): + def test_xs_other(self, float_frame, using_copy_on_write): float_frame_orig = float_frame.copy() # xs get column series = float_frame.xs("A", axis=1) @@ -69,8 +69,7 @@ def test_xs_other(self, float_frame, using_copy_on_write, warn_copy_on_write): # view is returned if possible series = float_frame.xs("A", axis=1) - with tm.assert_cow_warning(warn_copy_on_write): - series[:] = 5 + series[:] = 5 if using_copy_on_write: # but with CoW the view shouldn't propagate mutations tm.assert_series_equal(float_frame["A"], float_frame_orig["A"]) @@ -123,7 +122,7 @@ def test_xs_keep_level(self): result = df.xs((2008, "sat"), level=["year", "day"], drop_level=False) tm.assert_frame_equal(result, expected) - def test_xs_view(self, using_copy_on_write, warn_copy_on_write): + def test_xs_view(self, using_copy_on_write): # in 0.14 this will return a view if possible a copy otherwise, but # this is numpy dependent @@ -199,14 +198,13 @@ def test_xs_setting_with_copy_error( self, multiindex_dataframe_random_data, using_copy_on_write, - warn_copy_on_write, ): # this is a copy in 0.14 df = multiindex_dataframe_random_data df_orig = df.copy() result = df.xs("two", level="second") - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: result[:] = 10 else: # setting this will give a SettingWithCopyError @@ -217,14 +215,14 @@ def test_xs_setting_with_copy_error( tm.assert_frame_equal(df, df_orig) def test_xs_setting_with_copy_error_multiple( - self, four_level_index_dataframe, using_copy_on_write, warn_copy_on_write + self, four_level_index_dataframe, using_copy_on_write ): # this is a copy in 0.14 df = four_level_index_dataframe df_orig = df.copy() result = df.xs(("a", 4), level=["one", "four"]) - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: result[:] = 10 else: # setting this will give a SettingWithCopyError @@ -392,15 +390,14 @@ def test_xs_droplevel_false(self): expected = DataFrame({"a": [1]}) tm.assert_frame_equal(result, expected) - def test_xs_droplevel_false_view(self, using_copy_on_write, warn_copy_on_write): + def test_xs_droplevel_false_view(self, using_copy_on_write): # GH#37832 df = DataFrame([[1, 2, 3]], columns=Index(["a", "b", "c"])) result = df.xs("a", axis=1, drop_level=False) # check that result still views the same data as df assert np.shares_memory(result.iloc[:, 0]._values, df.iloc[:, 0]._values) - with tm.assert_cow_warning(warn_copy_on_write): - df.iloc[0, 0] = 2 + df.iloc[0, 0] = 2 if using_copy_on_write: # with copy on write the subset is never modified expected = DataFrame({"a": [1]}) diff --git a/pandas/tests/frame/methods/test_cov_corr.py b/pandas/tests/frame/methods/test_cov_corr.py index 04a08c8b9bc52..2a50137c2d6ef 100644 --- a/pandas/tests/frame/methods/test_cov_corr.py +++ b/pandas/tests/frame/methods/test_cov_corr.py @@ -207,7 +207,7 @@ def test_corr_nullable_integer(self, nullable_column, other_column, method): expected = DataFrame(np.ones((2, 2)), columns=["a", "b"], index=["a", "b"]) tm.assert_frame_equal(result, expected) - def test_corr_item_cache(self, using_copy_on_write, warn_copy_on_write): + def test_corr_item_cache(self, using_copy_on_write): # Check that corr does not lead to incorrect entries in item_cache df = DataFrame({"A": range(10)}) @@ -225,8 +225,7 @@ def test_corr_item_cache(self, using_copy_on_write, warn_copy_on_write): # Check that the corr didn't break link between ser and df ser.values[0] = 99 assert df.loc[0, "A"] == 99 - if not warn_copy_on_write: - assert df["A"] is ser + assert df["A"] is ser assert df.values[0, 0] == 99 @pytest.mark.parametrize("length", [2, 20, 200, 2000]) diff --git a/pandas/tests/frame/methods/test_fillna.py b/pandas/tests/frame/methods/test_fillna.py index 4f661b14ef201..df38ddc6c3116 100644 --- a/pandas/tests/frame/methods/test_fillna.py +++ b/pandas/tests/frame/methods/test_fillna.py @@ -20,18 +20,14 @@ class TestFillNA: - def test_fillna_dict_inplace_nonunique_columns( - self, using_copy_on_write, warn_copy_on_write - ): + def test_fillna_dict_inplace_nonunique_columns(self, using_copy_on_write): df = DataFrame( {"A": [np.nan] * 3, "B": [NaT, Timestamp(1), NaT], "C": [np.nan, "foo", 2]} ) df.columns = ["A", "A", "A"] orig = df[:] - # TODO(CoW-warn) better warning message - with tm.assert_cow_warning(warn_copy_on_write): - df.fillna({"A": 2}, inplace=True) + df.fillna({"A": 2}, inplace=True) # The first and third columns can be set inplace, while the second cannot. expected = DataFrame( @@ -750,15 +746,12 @@ def test_fillna_inplace_with_columns_limit_and_value(self): tm.assert_frame_equal(df, expected) @pytest.mark.parametrize("val", [-1, {"x": -1, "y": -1}]) - def test_inplace_dict_update_view( - self, val, using_copy_on_write, warn_copy_on_write - ): + def test_inplace_dict_update_view(self, val, using_copy_on_write): # GH#47188 df = DataFrame({"x": [np.nan, 2], "y": [np.nan, 2]}) df_orig = df.copy() result_view = df[:] - with tm.assert_cow_warning(warn_copy_on_write): - df.fillna(val, inplace=True) + df.fillna(val, inplace=True) expected = DataFrame({"x": [-1, 2.0], "y": [-1.0, 2]}) tm.assert_frame_equal(df, expected) if using_copy_on_write: diff --git a/pandas/tests/frame/methods/test_pop.py b/pandas/tests/frame/methods/test_pop.py index 3eb058015cd3d..617f0c3a27885 100644 --- a/pandas/tests/frame/methods/test_pop.py +++ b/pandas/tests/frame/methods/test_pop.py @@ -9,7 +9,7 @@ class TestDataFramePop: - def test_pop(self, float_frame, warn_copy_on_write): + def test_pop(self, float_frame): float_frame.columns.name = "baz" float_frame.pop("A") @@ -23,8 +23,7 @@ def test_pop(self, float_frame, warn_copy_on_write): # gh-10912: inplace ops cause caching issue a = DataFrame([[1, 2, 3], [4, 5, 6]], columns=["A", "B", "C"], index=["X", "Y"]) b = a.pop("B") - with tm.assert_cow_warning(warn_copy_on_write): - b += 1 + b += 1 # original frame expected = DataFrame([[1, 3], [4, 6]], columns=["A", "C"], index=["X", "Y"]) diff --git a/pandas/tests/frame/methods/test_rename.py b/pandas/tests/frame/methods/test_rename.py index c3bc96b44c807..b965a5d973fb6 100644 --- a/pandas/tests/frame/methods/test_rename.py +++ b/pandas/tests/frame/methods/test_rename.py @@ -164,13 +164,12 @@ def test_rename_multiindex(self): renamed = df.rename(index={"foo1": "foo3", "bar2": "bar3"}, level=0) tm.assert_index_equal(renamed.index, new_index) - def test_rename_nocopy(self, float_frame, using_copy_on_write, warn_copy_on_write): + def test_rename_nocopy(self, float_frame, using_copy_on_write): renamed = float_frame.rename(columns={"C": "foo"}, copy=False) assert np.shares_memory(renamed["foo"]._values, float_frame["C"]._values) - with tm.assert_cow_warning(warn_copy_on_write): - renamed.loc[:, "foo"] = 1.0 + renamed.loc[:, "foo"] = 1.0 if using_copy_on_write: assert not (float_frame["C"] == 1.0).all() else: diff --git a/pandas/tests/frame/methods/test_to_dict_of_blocks.py b/pandas/tests/frame/methods/test_to_dict_of_blocks.py index 217010ab2e7ee..19001f10e37e4 100644 --- a/pandas/tests/frame/methods/test_to_dict_of_blocks.py +++ b/pandas/tests/frame/methods/test_to_dict_of_blocks.py @@ -31,7 +31,7 @@ def test_no_copy_blocks(self, float_frame, using_copy_on_write): assert _last_df is not None and not _last_df[column].equals(df[column]) -def test_to_dict_of_blocks_item_cache(using_copy_on_write, warn_copy_on_write): +def test_to_dict_of_blocks_item_cache(using_copy_on_write): # Calling to_dict_of_blocks should not poison item_cache df = DataFrame({"a": [1, 2, 3, 4], "b": ["a", "b", "c", "d"]}) df["c"] = NumpyExtensionArray(np.array([1, 2, None, 3], dtype=object)) @@ -45,11 +45,6 @@ def test_to_dict_of_blocks_item_cache(using_copy_on_write, warn_copy_on_write): if using_copy_on_write: with pytest.raises(ValueError, match="read-only"): ser.values[0] = "foo" - elif warn_copy_on_write: - ser.values[0] = "foo" - assert df.loc[0, "b"] == "foo" - # with warning mode, the item cache is disabled - assert df["b"] is not ser else: # Check that the to_dict_of_blocks didn't break link between ser and df ser.values[0] = "foo" diff --git a/pandas/tests/frame/methods/test_update.py b/pandas/tests/frame/methods/test_update.py index 565619005d9f0..7ff8508c3b799 100644 --- a/pandas/tests/frame/methods/test_update.py +++ b/pandas/tests/frame/methods/test_update.py @@ -138,15 +138,12 @@ def test_update_datetime_tz(self): expected = DataFrame([pd.Timestamp("2019", tz="UTC")]) tm.assert_frame_equal(result, expected) - def test_update_datetime_tz_in_place(self, using_copy_on_write, warn_copy_on_write): + def test_update_datetime_tz_in_place(self, using_copy_on_write): # https://github.com/pandas-dev/pandas/issues/56227 result = DataFrame([pd.Timestamp("2019", tz="UTC")]) orig = result.copy() view = result[:] - with tm.assert_produces_warning( - FutureWarning if warn_copy_on_write else None, match="Setting a value" - ): - result.update(result + pd.Timedelta(days=1)) + result.update(result + pd.Timedelta(days=1)) expected = DataFrame([pd.Timestamp("2019-01-02", tz="UTC")]) tm.assert_frame_equal(result, expected) if not using_copy_on_write: @@ -170,17 +167,13 @@ def test_update_with_different_dtype(self, using_copy_on_write): ) tm.assert_frame_equal(df, expected) - def test_update_modify_view( - self, using_copy_on_write, warn_copy_on_write, using_infer_string - ): + def test_update_modify_view(self, using_copy_on_write, using_infer_string): # GH#47188 df = DataFrame({"A": ["1", np.nan], "B": ["100", np.nan]}) df2 = DataFrame({"A": ["a", "x"], "B": ["100", "200"]}) df2_orig = df2.copy() result_view = df2[:] - # TODO(CoW-warn) better warning message - with tm.assert_cow_warning(warn_copy_on_write): - df2.update(df) + df2.update(df) expected = DataFrame({"A": ["1", "x"], "B": ["100", "200"]}) tm.assert_frame_equal(df2, expected) if using_copy_on_write or using_infer_string: diff --git a/pandas/tests/frame/test_api.py b/pandas/tests/frame/test_api.py index c7b444045a0f2..0112e0093c102 100644 --- a/pandas/tests/frame/test_api.py +++ b/pandas/tests/frame/test_api.py @@ -326,7 +326,6 @@ def test_set_flags( allows_duplicate_labels, frame_or_series, using_copy_on_write, - warn_copy_on_write, ): obj = DataFrame({"A": [1, 2]}) key = (0, 0) @@ -354,15 +353,13 @@ def test_set_flags( else: assert np.may_share_memory(obj["A"].values, result["A"].values) - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[key] = 0 + result.iloc[key] = 0 if using_copy_on_write: assert obj.iloc[key] == 1 else: assert obj.iloc[key] == 0 # set back to 1 for test below - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[key] = 1 + result.iloc[key] = 1 # Now we do copy. result = obj.set_flags( diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index d33a7cdcf21c3..4fb0bbafc6879 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -2006,15 +2006,14 @@ def test_arith_list_of_arraylike_raise(to_add): to_add + df -def test_inplace_arithmetic_series_update(using_copy_on_write, warn_copy_on_write): +def test_inplace_arithmetic_series_update(using_copy_on_write): # https://github.com/pandas-dev/pandas/issues/36373 df = DataFrame({"A": [1, 2, 3]}) df_orig = df.copy() series = df["A"] vals = series._values - with tm.assert_cow_warning(warn_copy_on_write): - series += 1 + series += 1 if using_copy_on_write: assert series._values is not vals tm.assert_frame_equal(df, df_orig) diff --git a/pandas/tests/frame/test_block_internals.py b/pandas/tests/frame/test_block_internals.py index 22fff2116510a..36013e1ac949f 100644 --- a/pandas/tests/frame/test_block_internals.py +++ b/pandas/tests/frame/test_block_internals.py @@ -332,7 +332,7 @@ def test_is_mixed_type(self, float_frame, float_string_frame): assert not float_frame._is_mixed_type assert float_string_frame._is_mixed_type - def test_stale_cached_series_bug_473(self, using_copy_on_write, warn_copy_on_write): + def test_stale_cached_series_bug_473(self, using_copy_on_write): # this is chained, but ok with option_context("chained_assignment", None): Y = DataFrame( diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py index 9ff2b52bd35ff..20f147e94c514 100644 --- a/pandas/tests/frame/test_constructors.py +++ b/pandas/tests/frame/test_constructors.py @@ -287,27 +287,20 @@ def test_constructor_dtype_copy(self): new_df["col1"] = 200.0 assert orig_df["col1"][0] == 1.0 - def test_constructor_dtype_nocast_view_dataframe( - self, using_copy_on_write, warn_copy_on_write - ): + def test_constructor_dtype_nocast_view_dataframe(self, using_copy_on_write): df = DataFrame([[1, 2]]) should_be_view = DataFrame(df, dtype=df[0].dtype) if using_copy_on_write: should_be_view.iloc[0, 0] = 99 assert df.values[0, 0] == 1 else: - with tm.assert_cow_warning(warn_copy_on_write): - should_be_view.iloc[0, 0] = 99 + should_be_view.iloc[0, 0] = 99 assert df.values[0, 0] == 99 - def test_constructor_dtype_nocast_view_2d_array( - self, using_copy_on_write, warn_copy_on_write - ): + def test_constructor_dtype_nocast_view_2d_array(self, using_copy_on_write): df = DataFrame([[1, 2], [3, 4]], dtype="int64") if not using_copy_on_write: should_be_view = DataFrame(df.values, dtype=df[0].dtype) - # TODO(CoW-warn) this should warn - # with tm.assert_cow_warning(warn_copy_on_write): should_be_view.iloc[0, 0] = 97 assert df.values[0, 0] == 97 else: diff --git a/pandas/tests/generic/test_duplicate_labels.py b/pandas/tests/generic/test_duplicate_labels.py index 07f76810cbfc8..43d1c74d76db2 100644 --- a/pandas/tests/generic/test_duplicate_labels.py +++ b/pandas/tests/generic/test_duplicate_labels.py @@ -89,10 +89,8 @@ def test_preserve_getitem(self): assert df.loc[[0]].flags.allows_duplicate_labels is False assert df.loc[0, ["A"]].flags.allows_duplicate_labels is False - def test_ndframe_getitem_caching_issue( - self, request, using_copy_on_write, warn_copy_on_write - ): - if not (using_copy_on_write or warn_copy_on_write): + def test_ndframe_getitem_caching_issue(self, request, using_copy_on_write): + if not using_copy_on_write: request.applymarker(pytest.mark.xfail(reason="Unclear behavior.")) # NDFrame.__getitem__ will cache the first df['A']. May need to # invalidate that cache? Update the cached entries? diff --git a/pandas/tests/groupby/test_apply_mutate.py b/pandas/tests/groupby/test_apply_mutate.py index 29d82cce44807..e5028884e992b 100644 --- a/pandas/tests/groupby/test_apply_mutate.py +++ b/pandas/tests/groupby/test_apply_mutate.py @@ -75,7 +75,7 @@ def test_no_mutate_but_looks_like(): tm.assert_series_equal(result1, result2) -def test_apply_function_with_indexing(warn_copy_on_write): +def test_apply_function_with_indexing(): # GH: 33058 df = pd.DataFrame( {"col1": ["A", "A", "A", "B", "B", "B"], "col2": [1, 2, 3, 4, 5, 6]} @@ -86,9 +86,7 @@ def fn(x): return x.col2 msg = "DataFrameGroupBy.apply operated on the grouping columns" - with tm.assert_produces_warning( - DeprecationWarning, match=msg, raise_on_extra_warnings=not warn_copy_on_write - ): + with tm.assert_produces_warning(DeprecationWarning, match=msg): result = df.groupby(["col1"], as_index=False).apply(fn) expected = pd.Series( [1, 2, 0, 4, 5, 0], diff --git a/pandas/tests/groupby/test_reductions.py b/pandas/tests/groupby/test_reductions.py index 50103011693bc..1a32dcefed91a 100644 --- a/pandas/tests/groupby/test_reductions.py +++ b/pandas/tests/groupby/test_reductions.py @@ -1196,7 +1196,7 @@ def test_groupby_prod_with_int64_dtype(): tm.assert_frame_equal(result, expected) -def test_groupby_std_datetimelike(warn_copy_on_write): +def test_groupby_std_datetimelike(): # GH#48481 tdi = pd.timedelta_range("1 Day", periods=10000) ser = Series(tdi) diff --git a/pandas/tests/indexes/period/test_partial_slicing.py b/pandas/tests/indexes/period/test_partial_slicing.py index 4fab12f195dc0..a7873594ecade 100644 --- a/pandas/tests/indexes/period/test_partial_slicing.py +++ b/pandas/tests/indexes/period/test_partial_slicing.py @@ -12,9 +12,7 @@ class TestPeriodIndex: - def test_getitem_periodindex_duplicates_string_slice( - self, using_copy_on_write, warn_copy_on_write - ): + def test_getitem_periodindex_duplicates_string_slice(self, using_copy_on_write): # monotonic idx = PeriodIndex([2000, 2007, 2007, 2009, 2009], freq="Y-JUN") ts = Series(np.random.default_rng(2).standard_normal(len(idx)), index=idx) @@ -23,8 +21,7 @@ def test_getitem_periodindex_duplicates_string_slice( result = ts["2007"] expected = ts[1:3] tm.assert_series_equal(result, expected) - with tm.assert_cow_warning(warn_copy_on_write): - result[:] = 1 + result[:] = 1 if using_copy_on_write: tm.assert_series_equal(ts, original) else: diff --git a/pandas/tests/indexing/multiindex/test_chaining_and_caching.py b/pandas/tests/indexing/multiindex/test_chaining_and_caching.py index 014ba6fc12b72..24a111e283365 100644 --- a/pandas/tests/indexing/multiindex/test_chaining_and_caching.py +++ b/pandas/tests/indexing/multiindex/test_chaining_and_caching.py @@ -12,7 +12,7 @@ import pandas._testing as tm -def test_detect_chained_assignment(using_copy_on_write, warn_copy_on_write): +def test_detect_chained_assignment(using_copy_on_write): # Inplace ops, originally from: # https://stackoverflow.com/questions/20508968/series-fillna-in-a-multiindex-dataframe-does-not-fill-is-this-a-bug a = [12, 23] @@ -32,9 +32,6 @@ def test_detect_chained_assignment(using_copy_on_write, warn_copy_on_write): if using_copy_on_write: with tm.raises_chained_assignment_error(): zed["eyes"]["right"].fillna(value=555, inplace=True) - elif warn_copy_on_write: - with tm.assert_produces_warning(None): - zed["eyes"]["right"].fillna(value=555, inplace=True) else: msg = "A value is trying to be set on a copy of a slice from a DataFrame" with pytest.raises(SettingWithCopyError, match=msg): @@ -42,7 +39,7 @@ def test_detect_chained_assignment(using_copy_on_write, warn_copy_on_write): zed["eyes"]["right"].fillna(value=555, inplace=True) -def test_cache_updating(using_copy_on_write, warn_copy_on_write): +def test_cache_updating(using_copy_on_write): # 5216 # make sure that we don't try to set a dead cache a = np.random.default_rng(2).random((10, 3)) diff --git a/pandas/tests/indexing/multiindex/test_partial.py b/pandas/tests/indexing/multiindex/test_partial.py index 830c187a205a8..b68ab18fbc9b2 100644 --- a/pandas/tests/indexing/multiindex/test_partial.py +++ b/pandas/tests/indexing/multiindex/test_partial.py @@ -120,7 +120,6 @@ def test_partial_set( self, multiindex_year_month_day_dataframe_random_data, using_copy_on_write, - warn_copy_on_write, ): # GH #397 ymd = multiindex_year_month_day_dataframe_random_data diff --git a/pandas/tests/indexing/multiindex/test_setitem.py b/pandas/tests/indexing/multiindex/test_setitem.py index 22a0a49762097..17b00244c70f5 100644 --- a/pandas/tests/indexing/multiindex/test_setitem.py +++ b/pandas/tests/indexing/multiindex/test_setitem.py @@ -196,9 +196,7 @@ def test_multiindex_assignment(self): df.loc[4, "d"] = arr tm.assert_series_equal(df.loc[4, "d"], Series(arr, index=[8, 10], name="d")) - def test_multiindex_assignment_single_dtype( - self, using_copy_on_write, warn_copy_on_write - ): + def test_multiindex_assignment_single_dtype(self, using_copy_on_write): # GH3777 part 2b # single dtype arr = np.array([0.0, 1.0]) @@ -233,8 +231,7 @@ def test_multiindex_assignment_single_dtype( tm.assert_series_equal(result, exp) # scalar ok - with tm.assert_cow_warning(warn_copy_on_write): - df.loc[4, "c"] = 10 + df.loc[4, "c"] = 10 exp = Series(10, index=[8, 10], name="c", dtype="float64") tm.assert_series_equal(df.loc[4, "c"], exp) @@ -248,8 +245,7 @@ def test_multiindex_assignment_single_dtype( # But with a length-1 listlike column indexer this behaves like # `df.loc[4, "c"] = 0 - with tm.assert_cow_warning(warn_copy_on_write): - df.loc[4, ["c"]] = [0] + df.loc[4, ["c"]] = [0] assert (df.loc[4, "c"] == 0).all() def test_groupby_example(self): @@ -274,20 +270,16 @@ def test_groupby_example(self): new_vals = np.arange(df2.shape[0]) df.loc[name, "new_col"] = new_vals - def test_series_setitem( - self, multiindex_year_month_day_dataframe_random_data, warn_copy_on_write - ): + def test_series_setitem(self, multiindex_year_month_day_dataframe_random_data): ymd = multiindex_year_month_day_dataframe_random_data s = ymd["A"] - with tm.assert_cow_warning(warn_copy_on_write): - s[2000, 3] = np.nan + s[2000, 3] = np.nan assert isna(s.values[42:65]).all() assert notna(s.values[:42]).all() assert notna(s.values[65:]).all() - with tm.assert_cow_warning(warn_copy_on_write): - s[2000, 3, 10] = np.nan + s[2000, 3, 10] = np.nan assert isna(s.iloc[49]) with pytest.raises(KeyError, match="49"): @@ -423,7 +415,7 @@ def test_setitem_change_dtype(self, multiindex_dataframe_random_data): tm.assert_series_equal(reindexed["foo", "two"], s > s.median()) def test_set_column_scalar_with_loc( - self, multiindex_dataframe_random_data, using_copy_on_write, warn_copy_on_write + self, multiindex_dataframe_random_data, using_copy_on_write ): frame = multiindex_dataframe_random_data subset = frame.index[[1, 4, 5]] @@ -433,8 +425,7 @@ def test_set_column_scalar_with_loc( frame_original = frame.copy() col = frame["B"] - with tm.assert_cow_warning(warn_copy_on_write): - col[subset] = 97 + col[subset] = 97 if using_copy_on_write: # chained setitem doesn't work with CoW tm.assert_frame_equal(frame, frame_original) @@ -532,11 +523,11 @@ def test_frame_setitem_view_direct( def test_frame_setitem_copy_raises( - multiindex_dataframe_random_data, using_copy_on_write, warn_copy_on_write + multiindex_dataframe_random_data, using_copy_on_write ): # will raise/warn as its chained assignment df = multiindex_dataframe_random_data.T - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df["foo"]["one"] = 2 else: @@ -547,12 +538,12 @@ def test_frame_setitem_copy_raises( def test_frame_setitem_copy_no_write( - multiindex_dataframe_random_data, using_copy_on_write, warn_copy_on_write + multiindex_dataframe_random_data, using_copy_on_write ): frame = multiindex_dataframe_random_data.T expected = frame df = frame.copy() - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df["foo"]["one"] = 2 else: diff --git a/pandas/tests/indexing/test_chaining_and_caching.py b/pandas/tests/indexing/test_chaining_and_caching.py index 5acfb72c4a666..6dbe4f2b3ed3a 100644 --- a/pandas/tests/indexing/test_chaining_and_caching.py +++ b/pandas/tests/indexing/test_chaining_and_caching.py @@ -70,9 +70,7 @@ def test_setitem_cache_updating(self, do_ref): assert df.loc[0, "c"] == 0.0 assert df.loc[7, "c"] == 1.0 - def test_setitem_cache_updating_slices( - self, using_copy_on_write, warn_copy_on_write - ): + def test_setitem_cache_updating_slices(self, using_copy_on_write): # GH 7084 # not updating cache on series setting with slices expected = DataFrame( @@ -96,9 +94,7 @@ def test_setitem_cache_updating_slices( out_original = out.copy() for ix, row in df.iterrows(): v = out[row["C"]][six:eix] + row["D"] - with tm.raises_chained_assignment_error( - (ix == 0) or warn_copy_on_write or using_copy_on_write - ): + with tm.raises_chained_assignment_error((ix == 0) or using_copy_on_write): out[row["C"]][six:eix] = v if not using_copy_on_write: @@ -115,14 +111,12 @@ def test_setitem_cache_updating_slices( tm.assert_frame_equal(out, expected) tm.assert_series_equal(out["A"], expected["A"]) - def test_altering_series_clears_parent_cache( - self, using_copy_on_write, warn_copy_on_write - ): + def test_altering_series_clears_parent_cache(self, using_copy_on_write): # GH #33675 df = DataFrame([[1, 2], [3, 4]], index=["a", "b"], columns=["A", "B"]) ser = df["A"] - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: assert "A" not in df._item_cache else: assert "A" in df._item_cache @@ -210,9 +204,7 @@ def test_detect_chained_assignment(self, using_copy_on_write): tm.assert_frame_equal(df, expected) @pytest.mark.arm_slow - def test_detect_chained_assignment_raises( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_raises(self, using_copy_on_write): # test with the chaining df = DataFrame( { @@ -229,11 +221,6 @@ def test_detect_chained_assignment_raises( with tm.raises_chained_assignment_error(): df["A"][1] = -6 tm.assert_frame_equal(df, df_original) - elif warn_copy_on_write: - with tm.raises_chained_assignment_error(): - df["A"][0] = -5 - with tm.raises_chained_assignment_error(): - df["A"][1] = np.nan else: with pytest.raises(SettingWithCopyError, match=msg): with tm.raises_chained_assignment_error(): @@ -246,9 +233,7 @@ def test_detect_chained_assignment_raises( assert df["A"]._is_copy is None @pytest.mark.arm_slow - def test_detect_chained_assignment_fails( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_fails(self, using_copy_on_write): # Using a copy (the chain), fails df = DataFrame( { @@ -257,7 +242,7 @@ def test_detect_chained_assignment_fails( } ) - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df.loc[0]["A"] = -5 else: @@ -265,9 +250,7 @@ def test_detect_chained_assignment_fails( df.loc[0]["A"] = -5 @pytest.mark.arm_slow - def test_detect_chained_assignment_doc_example( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_doc_example(self, using_copy_on_write): # Doc example df = DataFrame( { @@ -278,7 +261,7 @@ def test_detect_chained_assignment_doc_example( assert df._is_copy is None indexer = df.a.str.startswith("o") - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df[indexer]["c"] = 42 else: @@ -286,16 +269,14 @@ def test_detect_chained_assignment_doc_example( df[indexer]["c"] = 42 @pytest.mark.arm_slow - def test_detect_chained_assignment_object_dtype( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_object_dtype(self, using_copy_on_write): expected = DataFrame({"A": [111, "bbb", "ccc"], "B": [1, 2, 3]}) df = DataFrame( {"A": Series(["aaa", "bbb", "ccc"], dtype=object), "B": [1, 2, 3]} ) df_original = df.copy() - if not using_copy_on_write and not warn_copy_on_write: + if not using_copy_on_write: with pytest.raises(SettingWithCopyError, match=msg): df.loc[0]["A"] = 111 @@ -303,10 +284,6 @@ def test_detect_chained_assignment_object_dtype( with tm.raises_chained_assignment_error(): df["A"][0] = 111 tm.assert_frame_equal(df, df_original) - elif warn_copy_on_write: - with tm.raises_chained_assignment_error(): - df["A"][0] = 111 - tm.assert_frame_equal(df, expected) else: with pytest.raises(SettingWithCopyError, match=msg): with tm.raises_chained_assignment_error(): @@ -358,10 +335,8 @@ def test_detect_chained_assignment_implicit_take(self): df["letters"] = df["letters"].apply(str.lower) @pytest.mark.arm_slow - def test_detect_chained_assignment_implicit_take2( - self, using_copy_on_write, warn_copy_on_write - ): - if using_copy_on_write or warn_copy_on_write: + def test_detect_chained_assignment_implicit_take2(self, using_copy_on_write): + if using_copy_on_write: pytest.skip("_is_copy is not always set for CoW") # Implicitly take 2 df = random_text(100000) @@ -415,9 +390,7 @@ def test_detect_chained_assignment_false_positives(self): str(df) @pytest.mark.arm_slow - def test_detect_chained_assignment_undefined_column( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_undefined_column(self, using_copy_on_write): # from SO: # https://stackoverflow.com/questions/24054495/potential-bug-setting-value-for-undefined-column-using-iloc df = DataFrame(np.arange(0, 9), columns=["count"]) @@ -428,18 +401,13 @@ def test_detect_chained_assignment_undefined_column( with tm.raises_chained_assignment_error(): df.iloc[0:5]["group"] = "a" tm.assert_frame_equal(df, df_original) - elif warn_copy_on_write: - with tm.raises_chained_assignment_error(): - df.iloc[0:5]["group"] = "a" else: with pytest.raises(SettingWithCopyError, match=msg): with tm.raises_chained_assignment_error(): df.iloc[0:5]["group"] = "a" @pytest.mark.arm_slow - def test_detect_chained_assignment_changing_dtype( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_changing_dtype(self, using_copy_on_write): # Mixed type setting but same dtype & changing dtype df = DataFrame( { @@ -451,7 +419,7 @@ def test_detect_chained_assignment_changing_dtype( ) df_original = df.copy() - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df.loc[2]["D"] = "foo" with tm.raises_chained_assignment_error(): @@ -474,7 +442,7 @@ def test_detect_chained_assignment_changing_dtype( with tm.raises_chained_assignment_error(): df["C"][2] = "foo" - def test_setting_with_copy_bug(self, using_copy_on_write, warn_copy_on_write): + def test_setting_with_copy_bug(self, using_copy_on_write): # operating on a copy df = DataFrame( {"a": list(range(4)), "b": list("ab.."), "c": ["a", "b", np.nan, "d"]} @@ -486,9 +454,6 @@ def test_setting_with_copy_bug(self, using_copy_on_write, warn_copy_on_write): with tm.raises_chained_assignment_error(): df[["c"]][mask] = df[["b"]][mask] tm.assert_frame_equal(df, df_original) - elif warn_copy_on_write: - with tm.raises_chained_assignment_error(): - df[["c"]][mask] = df[["b"]][mask] else: with pytest.raises(SettingWithCopyError, match=msg): df[["c"]][mask] = df[["b"]][mask] @@ -502,11 +467,9 @@ def test_setting_with_copy_bug_no_warning(self): # this should not raise df2["y"] = ["g", "h", "i"] - def test_detect_chained_assignment_warnings_errors( - self, using_copy_on_write, warn_copy_on_write - ): + def test_detect_chained_assignment_warnings_errors(self, using_copy_on_write): df = DataFrame({"A": ["aaa", "bbb", "ccc"], "B": [1, 2, 3]}) - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: with tm.raises_chained_assignment_error(): df.loc[0]["A"] = 111 return @@ -521,14 +484,14 @@ def test_detect_chained_assignment_warnings_errors( @pytest.mark.parametrize("rhs", [3, DataFrame({0: [1, 2, 3, 4]})]) def test_detect_chained_assignment_warning_stacklevel( - self, rhs, using_copy_on_write, warn_copy_on_write + self, rhs, using_copy_on_write ): # GH#42570 df = DataFrame(np.arange(25).reshape(5, 5)) df_original = df.copy() chained = df.loc[:3] with option_context("chained_assignment", "warn"): - if not using_copy_on_write and not warn_copy_on_write: + if not using_copy_on_write: with tm.assert_produces_warning(SettingWithCopyWarning) as t: chained[2] = rhs assert t[0].filename == __file__ diff --git a/pandas/tests/indexing/test_iat.py b/pandas/tests/indexing/test_iat.py index 5b8c4f2d4b9b9..4497c16efdfda 100644 --- a/pandas/tests/indexing/test_iat.py +++ b/pandas/tests/indexing/test_iat.py @@ -5,7 +5,6 @@ Series, period_range, ) -import pandas._testing as tm def test_iat(float_frame): @@ -31,9 +30,7 @@ def test_iat_getitem_series_with_period_index(): assert expected == result -def test_iat_setitem_item_cache_cleared( - indexer_ial, using_copy_on_write, warn_copy_on_write -): +def test_iat_setitem_item_cache_cleared(indexer_ial, using_copy_on_write): # GH#45684 data = {"x": np.arange(8, dtype=np.int64), "y": np.int64(0)} df = DataFrame(data).copy() @@ -41,11 +38,9 @@ def test_iat_setitem_item_cache_cleared( # previously this iat setting would split the block and fail to clear # the item_cache. - with tm.assert_cow_warning(warn_copy_on_write): - indexer_ial(df)[7, 0] = 9999 + indexer_ial(df)[7, 0] = 9999 - with tm.assert_cow_warning(warn_copy_on_write): - indexer_ial(df)[7, 1] = 1234 + indexer_ial(df)[7, 1] = 1234 assert df.iat[7, 1] == 1234 if not using_copy_on_write: diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 7b2a9dd99d925..5453c8be0e832 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -428,7 +428,7 @@ def test_iloc_getitem_slice_dups(self): tm.assert_frame_equal(df.iloc[10:, :2], df2) tm.assert_frame_equal(df.iloc[10:, 2:], df1) - def test_iloc_setitem(self, warn_copy_on_write): + def test_iloc_setitem(self): df = DataFrame( np.random.default_rng(2).standard_normal((4, 4)), index=np.arange(0, 8, 2), @@ -843,9 +843,7 @@ def test_iloc_empty_list_indexer_is_ok(self): df.iloc[[]], df.iloc[:0, :], check_index_type=True, check_column_type=True ) - def test_identity_slice_returns_new_object( - self, using_copy_on_write, warn_copy_on_write - ): + def test_identity_slice_returns_new_object(self, using_copy_on_write): # GH13873 original_df = DataFrame({"a": [1, 2, 3]}) sliced_df = original_df.iloc[:] @@ -856,8 +854,7 @@ def test_identity_slice_returns_new_object( # Setting using .loc[:, "a"] sets inplace so alters both sliced and orig # depending on CoW - with tm.assert_cow_warning(warn_copy_on_write): - original_df.loc[:, "a"] = [4, 4, 4] + original_df.loc[:, "a"] = [4, 4, 4] if using_copy_on_write: assert (sliced_df["a"] == [1, 2, 3]).all() else: @@ -868,8 +865,7 @@ def test_identity_slice_returns_new_object( assert sliced_series is not original_series # should also be a shallow copy - with tm.assert_cow_warning(warn_copy_on_write): - original_series[:3] = [7, 8, 9] + original_series[:3] = [7, 8, 9] if using_copy_on_write: # shallow copy not updated (CoW) assert all(sliced_series[:3] == [1, 2, 3]) @@ -1233,9 +1229,7 @@ def test_iloc_setitem_multicolumn_to_datetime(self): class TestILocErrors: # NB: this test should work for _any_ Series we can pass as # series_with_simple_index - def test_iloc_float_raises( - self, series_with_simple_index, frame_or_series, warn_copy_on_write - ): + def test_iloc_float_raises(self, series_with_simple_index, frame_or_series): # GH#4892 # float_indexers should raise exceptions # on appropriate Index types & accessors @@ -1252,10 +1246,7 @@ def test_iloc_float_raises( obj.iloc[3.0] with pytest.raises(IndexError, match=_slice_iloc_msg): - with tm.assert_cow_warning( - warn_copy_on_write and frame_or_series is DataFrame - ): - obj.iloc[3.0] = 0 + obj.iloc[3.0] = 0 def test_iloc_getitem_setitem_fancy_exceptions(self, float_frame): with pytest.raises(IndexingError, match="Too many indexers"): @@ -1423,7 +1414,7 @@ def test_frame_iloc_setitem_callable(self): class TestILocSeries: - def test_iloc(self, using_copy_on_write, warn_copy_on_write): + def test_iloc(self, using_copy_on_write): ser = Series( np.random.default_rng(2).standard_normal(10), index=list(range(0, 20, 2)) ) @@ -1442,8 +1433,7 @@ def test_iloc(self, using_copy_on_write, warn_copy_on_write): # test slice is a view with tm.assert_produces_warning(None): # GH#45324 make sure we aren't giving a spurious FutureWarning - with tm.assert_cow_warning(warn_copy_on_write): - result[:] = 0 + result[:] = 0 if using_copy_on_write: tm.assert_series_equal(ser, ser_original) else: diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index b155c3aabd287..193c296115479 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -832,8 +832,7 @@ def test_loc_setitem_frame_mixed_labels(self): df.loc[0, [1, 2]] = [5, 6] tm.assert_frame_equal(df, expected) - @pytest.mark.filterwarnings("ignore:Setting a value on a view:FutureWarning") - def test_loc_setitem_frame_multiples(self, warn_copy_on_write): + def test_loc_setitem_frame_multiples(self): # multiple setting df = DataFrame( {"A": ["foo", "bar", "baz"], "B": Series(range(3), dtype=np.int64)} @@ -1090,9 +1089,7 @@ def test_loc_empty_list_indexer_is_ok(self): df.loc[[]], df.iloc[:0, :], check_index_type=True, check_column_type=True ) - def test_identity_slice_returns_new_object( - self, using_copy_on_write, warn_copy_on_write - ): + def test_identity_slice_returns_new_object(self, using_copy_on_write): # GH13873 original_df = DataFrame({"a": [1, 2, 3]}) @@ -1106,8 +1103,7 @@ def test_identity_slice_returns_new_object( # Setting using .loc[:, "a"] sets inplace so alters both sliced and orig # depending on CoW - with tm.assert_cow_warning(warn_copy_on_write): - original_df.loc[:, "a"] = [4, 4, 4] + original_df.loc[:, "a"] = [4, 4, 4] if using_copy_on_write: assert (sliced_df["a"] == [1, 2, 3]).all() else: @@ -1115,7 +1111,7 @@ def test_identity_slice_returns_new_object( # These should not return copies df = DataFrame(np.random.default_rng(2).standard_normal((10, 4))) - if using_copy_on_write or warn_copy_on_write: + if using_copy_on_write: assert df[0] is not df.loc[:, 0] else: assert df[0] is df.loc[:, 0] @@ -1126,8 +1122,7 @@ def test_identity_slice_returns_new_object( assert sliced_series is not original_series assert original_series[:] is not original_series - with tm.assert_cow_warning(warn_copy_on_write): - original_series[:3] = [7, 8, 9] + original_series[:3] = [7, 8, 9] if using_copy_on_write: assert all(sliced_series[:3] == [1, 2, 3]) else: @@ -2651,9 +2646,7 @@ def test_loc_setitem_boolean_and_column(self, float_frame): expected = DataFrame(values, index=expected.index, columns=expected.columns) tm.assert_frame_equal(float_frame, expected) - def test_loc_setitem_ndframe_values_alignment( - self, using_copy_on_write, warn_copy_on_write - ): + def test_loc_setitem_ndframe_values_alignment(self, using_copy_on_write): # GH#45501 df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) df.loc[[False, False, True], ["a"]] = DataFrame( @@ -2676,8 +2669,7 @@ def test_loc_setitem_ndframe_values_alignment( df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) df_orig = df.copy() ser = df["a"] - with tm.assert_cow_warning(warn_copy_on_write): - ser.loc[[False, False, True]] = Series([10, 11, 12], index=[2, 1, 0]) + ser.loc[[False, False, True]] = Series([10, 11, 12], index=[2, 1, 0]) if using_copy_on_write: tm.assert_frame_equal(df, df_orig) else: diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 848e1d5bc47a6..a22d4666e3b2d 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -2160,3 +2160,19 @@ def test_json_pos_args_deprecation(): with tm.assert_produces_warning(FutureWarning, match=msg): buf = BytesIO() df.to_json(buf, "split") + + +@td.skip_if_no("pyarrow") +def test_to_json_ea_null(): + # GH#57224 + df = DataFrame( + { + "a": Series([1, NA], dtype="int64[pyarrow]"), + "b": Series([2, NA], dtype="Int64"), + } + ) + result = df.to_json(orient="records", lines=True) + expected = """{"a":1,"b":2} +{"a":null,"b":null} +""" + assert result == expected diff --git a/pandas/tests/series/accessors/test_dt_accessor.py b/pandas/tests/series/accessors/test_dt_accessor.py index 2365ff62b1680..9de14b3a7c112 100644 --- a/pandas/tests/series/accessors/test_dt_accessor.py +++ b/pandas/tests/series/accessors/test_dt_accessor.py @@ -281,7 +281,7 @@ def test_dt_accessor_ambiguous_freq_conversions(self): expected = Series(exp_values, name="xxx") tm.assert_series_equal(ser, expected) - def test_dt_accessor_not_writeable(self, using_copy_on_write, warn_copy_on_write): + def test_dt_accessor_not_writeable(self, using_copy_on_write): # no setting allowed ser = Series(date_range("20130101", periods=5, freq="D"), name="xxx") with pytest.raises(ValueError, match="modifications"): @@ -293,11 +293,6 @@ def test_dt_accessor_not_writeable(self, using_copy_on_write, warn_copy_on_write if using_copy_on_write: with tm.raises_chained_assignment_error(): ser.dt.hour[0] = 5 - elif warn_copy_on_write: - with tm.assert_produces_warning( - FutureWarning, match="ChainedAssignmentError" - ): - ser.dt.hour[0] = 5 else: with pytest.raises(SettingWithCopyError, match=msg): ser.dt.hour[0] = 5 diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 191104b3f330f..50c167f3f3a28 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -101,14 +101,13 @@ def test_basic_getitem_dt64tz_values(): assert result == expected -def test_getitem_setitem_ellipsis(using_copy_on_write, warn_copy_on_write): +def test_getitem_setitem_ellipsis(using_copy_on_write): s = Series(np.random.default_rng(2).standard_normal(10)) result = s[...] tm.assert_series_equal(result, s) - with tm.assert_cow_warning(warn_copy_on_write): - s[...] = 5 + s[...] = 5 if not using_copy_on_write: assert (result == 5).all() @@ -243,7 +242,7 @@ def test_basic_getitem_setitem_corner(datetime_series): datetime_series[[5, [None, None]]] = 2 -def test_slice(string_series, object_series, using_copy_on_write, warn_copy_on_write): +def test_slice(string_series, object_series, using_copy_on_write): original = string_series.copy() numSlice = string_series[10:20] numSliceEnd = string_series[-10:] @@ -260,8 +259,7 @@ def test_slice(string_series, object_series, using_copy_on_write, warn_copy_on_w # Test return view. sl = string_series[10:20] - with tm.assert_cow_warning(warn_copy_on_write): - sl[:] = 0 + sl[:] = 0 if using_copy_on_write: # Doesn't modify parent (CoW) diff --git a/pandas/tests/series/methods/test_copy.py b/pandas/tests/series/methods/test_copy.py index 23dbe85075916..ea439fb5a3263 100644 --- a/pandas/tests/series/methods/test_copy.py +++ b/pandas/tests/series/methods/test_copy.py @@ -10,7 +10,7 @@ class TestCopy: @pytest.mark.parametrize("deep", ["default", None, False, True]) - def test_copy(self, deep, using_copy_on_write, warn_copy_on_write): + def test_copy(self, deep, using_copy_on_write): ser = Series(np.arange(10), dtype="float64") # default deep is True @@ -27,8 +27,7 @@ def test_copy(self, deep, using_copy_on_write, warn_copy_on_write): else: assert not np.may_share_memory(ser.values, ser2.values) - with tm.assert_cow_warning(warn_copy_on_write and deep is False): - ser2[::2] = np.nan + ser2[::2] = np.nan if deep is not False or using_copy_on_write: # Did not modify original Series diff --git a/pandas/tests/series/methods/test_get_numeric_data.py b/pandas/tests/series/methods/test_get_numeric_data.py index 8325cc884ebcb..11dc6d5c57162 100644 --- a/pandas/tests/series/methods/test_get_numeric_data.py +++ b/pandas/tests/series/methods/test_get_numeric_data.py @@ -7,17 +7,14 @@ class TestGetNumericData: - def test_get_numeric_data_preserve_dtype( - self, using_copy_on_write, warn_copy_on_write - ): + def test_get_numeric_data_preserve_dtype(self, using_copy_on_write): # get the numeric data obj = Series([1, 2, 3]) result = obj._get_numeric_data() tm.assert_series_equal(result, obj) # returned object is a shallow copy - with tm.assert_cow_warning(warn_copy_on_write): - result.iloc[0] = 0 + result.iloc[0] = 0 if using_copy_on_write: assert obj.iloc[0] == 1 else: diff --git a/pandas/tests/series/methods/test_rename.py b/pandas/tests/series/methods/test_rename.py index 119654bd19b3f..e59389ab069d3 100644 --- a/pandas/tests/series/methods/test_rename.py +++ b/pandas/tests/series/methods/test_rename.py @@ -169,13 +169,12 @@ def test_rename_error_arg(self): with pytest.raises(KeyError, match=match): ser.rename({2: 9}, errors="raise") - def test_rename_copy_false(self, using_copy_on_write, warn_copy_on_write): + def test_rename_copy_false(self, using_copy_on_write): # GH 46889 ser = Series(["foo", "bar"]) ser_orig = ser.copy() shallow_copy = ser.rename({1: 9}, copy=False) - with tm.assert_cow_warning(warn_copy_on_write): - ser[0] = "foobar" + ser[0] = "foobar" if using_copy_on_write: assert ser_orig[0] == shallow_copy[0] assert ser_orig[1] == shallow_copy[9] diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index 55ca1f98f6d6c..a1e08f484ebba 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -891,14 +891,12 @@ def test_constructor_invalid_coerce_ints_with_float_nan(self, any_int_numpy_dtyp with pytest.raises(IntCastingNaNError, match=msg): Series(np.array(vals), dtype=any_int_numpy_dtype) - def test_constructor_dtype_no_cast(self, using_copy_on_write, warn_copy_on_write): + def test_constructor_dtype_no_cast(self, using_copy_on_write): # see gh-1572 s = Series([1, 2, 3]) s2 = Series(s, dtype=np.int64) - warn = FutureWarning if warn_copy_on_write else None - with tm.assert_produces_warning(warn): - s2[1] = 5 + s2[1] = 5 if using_copy_on_write: assert s[1] == 2 else: