Skip to content

Commit 64cc028

Browse files
authored
Backport PR #52029 on branch 2.0.x (BUG-CoW: from_records not tracking references when called with df) (#52055)
1 parent 1c5dd84 commit 64cc028

File tree

4 files changed

+31
-3
lines changed

4 files changed

+31
-3
lines changed

doc/source/whatsnew/v2.0.0.rst

+3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ Copy-on-Write improvements
197197
behavior when the NumPy array is modified after creation of the
198198
:class:`DataFrame`.
199199

200+
- The :meth:`DataFrame.from_records` will now respect Copy-on-Write when called
201+
with a :class:`DataFrame`.
202+
200203
- Trying to set values using chained assignment (for example, ``df["a"][1:3] = 0``)
201204
will now always raise an warning when Copy-on-Write is enabled. In this mode,
202205
chained assignment can never work because we are always setting into a temporary

pandas/core/frame.py

+11
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,17 @@ def from_records(
21802180
2 1 c
21812181
3 0 d
21822182
"""
2183+
if isinstance(data, DataFrame):
2184+
if columns is not None:
2185+
if is_scalar(columns):
2186+
columns = [columns]
2187+
data = data[columns]
2188+
if index is not None:
2189+
data = data.set_index(index)
2190+
if exclude is not None:
2191+
data = data.drop(columns=exclude)
2192+
return data.copy(deep=False)
2193+
21832194
result_index = None
21842195

21852196
# Make a copy of the input columns so we can modify it

pandas/tests/copy_view/test_constructors.py

+14
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,17 @@ def test_frame_from_numpy_array(using_copy_on_write, copy, using_array_manager):
231231
assert not np.shares_memory(get_array(df, 0), arr)
232232
else:
233233
assert np.shares_memory(get_array(df, 0), arr)
234+
235+
236+
def test_dataframe_from_records_with_dataframe(using_copy_on_write):
237+
df = DataFrame({"a": [1, 2, 3]})
238+
df_orig = df.copy()
239+
df2 = DataFrame.from_records(df)
240+
if using_copy_on_write:
241+
assert not df._mgr._has_no_reference(0)
242+
assert np.shares_memory(get_array(df, "a"), get_array(df2, "a"))
243+
df2.iloc[0, 0] = 100
244+
if using_copy_on_write:
245+
tm.assert_frame_equal(df, df_orig)
246+
else:
247+
tm.assert_frame_equal(df, df2)

pandas/tests/frame/constructors/test_from_records.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,12 @@ def test_from_records_bad_index_column(self):
193193
# should fail
194194
msg = "|".join(
195195
[
196-
r"Length of values \(10\) does not match length of index \(1\)",
196+
r"'None of \[2\] are in the columns'",
197197
]
198198
)
199-
with pytest.raises(ValueError, match=msg):
199+
with pytest.raises(KeyError, match=msg):
200200
DataFrame.from_records(df, index=[2])
201-
with pytest.raises(KeyError, match=r"^2$"):
201+
with pytest.raises(KeyError, match=msg):
202202
DataFrame.from_records(df, index=2)
203203

204204
def test_from_records_non_tuple(self):

0 commit comments

Comments
 (0)