From 9373936b2651448f49cf91bbe4b7cd56bcc10d47 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 26 Nov 2025 18:05:02 +0100 Subject: [PATCH 1/3] API: partial revert of returning read-only EAs from .array/.values --- pandas/core/indexes/base.py | 4 ++-- pandas/core/internals/blocks.py | 5 +++-- pandas/core/series.py | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index faa63f71b3747..f1fb7870b3e5d 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5023,8 +5023,8 @@ def array(self) -> ExtensionArray: from pandas.core.arrays.numpy_ import NumpyExtensionArray array = NumpyExtensionArray(array) - array = array.view() - array._readonly = True + # array = array.view() + # array._readonly = True return array @property diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 32d6c8f738851..72694edd324cc 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -2387,7 +2387,8 @@ def external_values(values: ArrayLike) -> ArrayLike: values.flags.writeable = False else: # ExtensionArrays - values = values.view() - values._readonly = True + # values = values.view() + # values._readonly = True + pass return values diff --git a/pandas/core/series.py b/pandas/core/series.py index 89c59b6788cd2..e9d221c3558a1 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -819,8 +819,8 @@ def _references(self) -> BlockValuesRefs: @property def array(self) -> ExtensionArray: arr = self._mgr.array_values() - arr = arr.view() - arr._readonly = True + # arr = arr.view() + # arr._readonly = True return arr def __len__(self) -> int: From 3d7d16233faeca033851213afd7e2666ca1653df Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 26 Nov 2025 22:41:51 +0100 Subject: [PATCH 2/3] tmp test --- pandas/tests/copy_view/test_array.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/copy_view/test_array.py b/pandas/tests/copy_view/test_array.py index aed7afb8fb123..2b2bc7196bc9b 100644 --- a/pandas/tests/copy_view/test_array.py +++ b/pandas/tests/copy_view/test_array.py @@ -19,11 +19,11 @@ "method", [ lambda ser: ser.values, - lambda ser: np.asarray(ser.array), + # lambda ser: np.asarray(ser.array), lambda ser: np.asarray(ser), lambda ser: np.array(ser, copy=False), ], - ids=["values", "array", "np.asarray", "np.array"], + ids=["values", "np.asarray", "np.array"], ) def test_series_values(method): ser = Series([1, 2, 3], name="name") @@ -109,12 +109,12 @@ def test_series_to_numpy(): @pytest.mark.parametrize( "method", [ - lambda ser: np.asarray(ser.array), + # lambda ser: np.asarray(ser.array), lambda ser: np.asarray(ser), lambda ser: np.asarray(ser, dtype="int64"), lambda ser: np.array(ser, copy=False), ], - ids=["array", "np.asarray", "np.asarray-dtype", "np.array"], + ids=["np.asarray", "np.asarray-dtype", "np.array"], ) def test_series_values_ea_dtypes(method): ser = Series([1, 2, 3], dtype="Int64") From 809546f245c4ef2a09249701320d9581064c5270 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 1 Dec 2025 14:17:10 +0100 Subject: [PATCH 3/3] add comments + update tests --- pandas/core/indexes/base.py | 1 + pandas/core/internals/blocks.py | 1 + pandas/core/series.py | 1 + pandas/tests/copy_view/test_array.py | 43 ++++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 90f7837f08e09..7cb43c49ab388 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5023,6 +5023,7 @@ def array(self) -> ExtensionArray: from pandas.core.arrays.numpy_ import NumpyExtensionArray array = NumpyExtensionArray(array) + # TODO decide on read-only https://github.com/pandas-dev/pandas/issues/63099 # array = array.view() # array._readonly = True return array diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 67941b7dc0b77..544a48a96b955 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -2387,6 +2387,7 @@ def external_values(values: ArrayLike) -> ArrayLike: values.flags.writeable = False else: # ExtensionArrays + # TODO decide on read-only https://github.com/pandas-dev/pandas/issues/63099 # values = values.view() # values._readonly = True pass diff --git a/pandas/core/series.py b/pandas/core/series.py index f2e9f2f41d7a7..09d630f78b776 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -821,6 +821,7 @@ def _references(self) -> BlockValuesRefs: @property def array(self) -> ExtensionArray: arr = self._mgr.array_values() + # TODO decide on read-only https://github.com/pandas-dev/pandas/issues/63099 # arr = arr.view() # arr._readonly = True return arr diff --git a/pandas/tests/copy_view/test_array.py b/pandas/tests/copy_view/test_array.py index 2b2bc7196bc9b..e6068f9713bfd 100644 --- a/pandas/tests/copy_view/test_array.py +++ b/pandas/tests/copy_view/test_array.py @@ -19,18 +19,27 @@ "method", [ lambda ser: ser.values, - # lambda ser: np.asarray(ser.array), + lambda ser: np.asarray(ser.array), lambda ser: np.asarray(ser), lambda ser: np.array(ser, copy=False), ], - ids=["values", "np.asarray", "np.array"], + ids=["values", "array", "np.asarray", "np.array"], ) -def test_series_values(method): +def test_series_values(request, method): ser = Series([1, 2, 3], name="name") ser_orig = ser.copy() arr = method(ser) + if request.node.callspec.id == "array": + # https://github.com/pandas-dev/pandas/issues/63099 + # .array for now does not return a read-only view + assert arr.flags.writeable is True + # updating the array updates the series + arr[0] = 0 + assert ser.iloc[0] == 0 + return + # .values still gives a view but is read-only assert np.shares_memory(arr, get_array(ser, "name")) assert arr.flags.writeable is False @@ -109,20 +118,42 @@ def test_series_to_numpy(): @pytest.mark.parametrize( "method", [ - # lambda ser: np.asarray(ser.array), + lambda ser: np.asarray(ser.values), + lambda ser: np.asarray(ser.array), lambda ser: np.asarray(ser), lambda ser: np.asarray(ser, dtype="int64"), lambda ser: np.array(ser, copy=False), ], - ids=["np.asarray", "np.asarray-dtype", "np.array"], + ids=["values", "array", "np.asarray", "np.asarray-dtype", "np.array"], ) -def test_series_values_ea_dtypes(method): +def test_series_values_ea_dtypes(request, method): ser = Series([1, 2, 3], dtype="Int64") + ser_orig = ser.copy() + arr = method(ser) + if request.node.callspec.id in ("values", "array"): + # https://github.com/pandas-dev/pandas/issues/63099 + # .array/values for now does not return a read-only view + assert arr.flags.writeable is True + # updating the array updates the series + arr[0] = 0 + assert ser.iloc[0] == 0 + return + + # conversion to ndarray gives a view but is read-only assert np.shares_memory(arr, get_array(ser)) assert arr.flags.writeable is False + # mutating series through arr therefore doesn't work + with pytest.raises(ValueError, match="read-only"): + arr[0] = 0 + tm.assert_series_equal(ser, ser_orig) + + # mutating the series itself still works + ser.iloc[0] = 0 + assert ser.values[0] == 0 + @pytest.mark.parametrize( "method",