From 96e92b0b2cbbde87e2c8f57f69a7e27b9e2a3e93 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Wed, 14 Oct 2020 18:26:25 +0300 Subject: [PATCH 01/10] TST: add test for raise --- pandas/tests/frame/test_arithmetic.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 94f813fd08128..ee132170f1bb0 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1577,3 +1577,13 @@ def test_arith_reindex_with_duplicates(): result = df1 + df2 expected = pd.DataFrame([[np.nan, 0, 0]], columns=["first", "second", "second"]) tm.assert_frame_equal(result, expected) + + +def test_arith_list_of_arraylike_raise(): + # GH 36702. Raise when trying to add list of array-like to DataFrame + df = pd.DataFrame({'x': [1, 2], 'y': [1, 2]}) + ser = pd.Series([1, 1]) + + msg = "Cannot perform arithmetic on DataFrame or Series and a list of array-like." + with pytest.raises(ValueError, match=msg): + result = df + [ser, ser] From 79e98cd962114d5eecb75124479a2666a4e7739e Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Wed, 14 Oct 2020 18:35:07 +0300 Subject: [PATCH 02/10] BUG: add initial bugfix, edit error message --- pandas/core/ops/__init__.py | 6 +++++- pandas/tests/frame/test_arithmetic.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index 27b6ad37bb612..0995f37802382 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -13,7 +13,7 @@ from pandas._typing import Level from pandas.util._decorators import Appender -from pandas.core.dtypes.common import is_list_like +from pandas.core.dtypes.common import is_array_like, is_list_like from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries from pandas.core.dtypes.missing import isna @@ -311,6 +311,10 @@ def to_series(right): ) elif is_list_like(right) and not isinstance(right, (ABCSeries, ABCDataFrame)): + # GH 36702. Raise when attempting arithmetic with list of array-like. + if any([is_array_like(el) for el in right]): + raise ValueError(f"Unable to coerce list of {type(right[0])} " + "to Series/DataFrame") # GH17901 right = to_series(right) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index ee132170f1bb0..3fedbbf498072 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1584,6 +1584,6 @@ def test_arith_list_of_arraylike_raise(): df = pd.DataFrame({'x': [1, 2], 'y': [1, 2]}) ser = pd.Series([1, 1]) - msg = "Cannot perform arithmetic on DataFrame or Series and a list of array-like." + msg = f"Unable to coerce list of {type(ser)} to Series/DataFrame" with pytest.raises(ValueError, match=msg): result = df + [ser, ser] From 7a0e20c38681a06f542f63c2cf30c158d18ad058 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 10:16:40 +0300 Subject: [PATCH 03/10] DOC: add whatsnew --- doc/source/whatsnew/v1.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index a963442ecda1c..2d5f2672f7880 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -492,6 +492,7 @@ Other - Fixed metadata propagation in the :class:`Series.dt` and :class:`Series.str` accessors (:issue:`28283`) - Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`) - Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError``, from a bare ``Exception`` previously (:issue:`35744`) +- Bug in :class:`DataFrame` allowing arithmetic operations with list of array-likes with undefined results. Behavior changed to raising ``ValueError`` (:issue:`36702`) .. --------------------------------------------------------------------------- From 0b461b1725ff95134457d43770a74e735eeb6926 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 10:20:07 +0300 Subject: [PATCH 04/10] CLN: run black pandas --- pandas/core/ops/__init__.py | 5 +++-- pandas/tests/frame/test_arithmetic.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index 0995f37802382..3892d5b394e29 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -313,8 +313,9 @@ def to_series(right): elif is_list_like(right) and not isinstance(right, (ABCSeries, ABCDataFrame)): # GH 36702. Raise when attempting arithmetic with list of array-like. if any([is_array_like(el) for el in right]): - raise ValueError(f"Unable to coerce list of {type(right[0])} " - "to Series/DataFrame") + raise ValueError( + f"Unable to coerce list of {type(right[0])} " "to Series/DataFrame" + ) # GH17901 right = to_series(right) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 3fedbbf498072..28ecd37c453ba 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1581,7 +1581,7 @@ def test_arith_reindex_with_duplicates(): def test_arith_list_of_arraylike_raise(): # GH 36702. Raise when trying to add list of array-like to DataFrame - df = pd.DataFrame({'x': [1, 2], 'y': [1, 2]}) + df = pd.DataFrame({"x": [1, 2], "y": [1, 2]}) ser = pd.Series([1, 1]) msg = f"Unable to coerce list of {type(ser)} to Series/DataFrame" From 309b3db32a984015b2200c9e80b5b83c693b89a8 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 10:24:08 +0300 Subject: [PATCH 05/10] CLN: fix flake8 errors --- pandas/core/ops/__init__.py | 2 +- pandas/tests/frame/test_arithmetic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index 3892d5b394e29..b2931ad77273d 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -312,7 +312,7 @@ def to_series(right): elif is_list_like(right) and not isinstance(right, (ABCSeries, ABCDataFrame)): # GH 36702. Raise when attempting arithmetic with list of array-like. - if any([is_array_like(el) for el in right]): + if any(is_array_like(el) for el in right): raise ValueError( f"Unable to coerce list of {type(right[0])} " "to Series/DataFrame" ) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 28ecd37c453ba..90d2f892dda7f 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1586,4 +1586,4 @@ def test_arith_list_of_arraylike_raise(): msg = f"Unable to coerce list of {type(ser)} to Series/DataFrame" with pytest.raises(ValueError, match=msg): - result = df + [ser, ser] + df + [ser, ser] From e7561da71a4e3a9211a100218c4efb1b5409de84 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 11:43:49 +0300 Subject: [PATCH 06/10] CLN: remove unnecessary string split --- pandas/core/ops/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index b2931ad77273d..fb3005484b2f1 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -314,7 +314,7 @@ def to_series(right): # GH 36702. Raise when attempting arithmetic with list of array-like. if any(is_array_like(el) for el in right): raise ValueError( - f"Unable to coerce list of {type(right[0])} " "to Series/DataFrame" + f"Unable to coerce list of {type(right[0])} to Series/DataFrame" ) # GH17901 right = to_series(right) From a464f6760c14f37d4a7b7fd4869201336e439494 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 16:25:09 +0300 Subject: [PATCH 07/10] DOC: move whatsnew to Numeric section --- doc/source/whatsnew/v1.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 8f95fe3e6e5c2..ecd6ebfabdb6e 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -371,6 +371,7 @@ Numeric - Bug in :meth:`DataFrame.diff` with ``datetime64`` dtypes including ``NaT`` values failing to fill ``NaT`` results correctly (:issue:`32441`) - Bug in :class:`DataFrame` arithmetic ops incorrectly accepting keyword arguments (:issue:`36843`) - Bug in :class:`IntervalArray` comparisons with :class:`Series` not returning :class:`Series` (:issue:`36908`) +- Bug in :class:`DataFrame` allowing arithmetic operations with list of array-likes with undefined results. Behavior changed to raising ``ValueError`` (:issue:`36702`) Conversion ^^^^^^^^^^ @@ -494,7 +495,6 @@ Other - Fixed metadata propagation in the :class:`Series.dt` and :class:`Series.str` accessors (:issue:`28283`) - Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`) - Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError``, from a bare ``Exception`` previously (:issue:`35744`) -- Bug in :class:`DataFrame` allowing arithmetic operations with list of array-likes with undefined results. Behavior changed to raising ``ValueError`` (:issue:`36702`) .. --------------------------------------------------------------------------- From 0acac063ecb50d5f4ef03d4c70ab1e9760f73cf4 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 15 Oct 2020 16:46:46 +0300 Subject: [PATCH 08/10] TST: add reverse op and one-element list to the test --- pandas/tests/frame/test_arithmetic.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 90d2f892dda7f..7915d8a1c965d 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1579,11 +1579,15 @@ def test_arith_reindex_with_duplicates(): tm.assert_frame_equal(result, expected) -def test_arith_list_of_arraylike_raise(): +@pytest.mark.parametrize("arg1", [pd.DataFrame({"x": [1, 2], "y": [1, 2]})]) +@pytest.mark.parametrize( + "arg2", [[pd.Series([1, 1])], [pd.Series([1, 1]), pd.Series([1, 1])]] +) +def test_arith_list_of_arraylike_raise(arg1, arg2): # GH 36702. Raise when trying to add list of array-like to DataFrame - df = pd.DataFrame({"x": [1, 2], "y": [1, 2]}) - ser = pd.Series([1, 1]) - msg = f"Unable to coerce list of {type(ser)} to Series/DataFrame" + msg = f"Unable to coerce list of {type(arg2[0])} to Series/DataFrame" + with pytest.raises(ValueError, match=msg): + arg1 + arg2 with pytest.raises(ValueError, match=msg): - df + [ser, ser] + arg2 + arg1 From 26d6aba431afeb8e60fe3ee0e73137919cb8be20 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Fri, 16 Oct 2020 12:07:35 +0300 Subject: [PATCH 09/10] TST: move DataFrame inside the test --- pandas/tests/frame/test_arithmetic.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 7915d8a1c965d..2c04473d50851 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1579,15 +1579,15 @@ def test_arith_reindex_with_duplicates(): tm.assert_frame_equal(result, expected) -@pytest.mark.parametrize("arg1", [pd.DataFrame({"x": [1, 2], "y": [1, 2]})]) @pytest.mark.parametrize( - "arg2", [[pd.Series([1, 1])], [pd.Series([1, 1]), pd.Series([1, 1])]] + "to_add", [[pd.Series([1, 1])], [pd.Series([1, 1]), pd.Series([1, 1])]] ) -def test_arith_list_of_arraylike_raise(arg1, arg2): +def test_arith_list_of_arraylike_raise(to_add): # GH 36702. Raise when trying to add list of array-like to DataFrame + df = pd.DataFrame({"x": [1, 2], "y": [1, 2]}) - msg = f"Unable to coerce list of {type(arg2[0])} to Series/DataFrame" + msg = f"Unable to coerce list of {type(to_add[0])} to Series/DataFrame" with pytest.raises(ValueError, match=msg): - arg1 + arg2 + df + to_add with pytest.raises(ValueError, match=msg): - arg2 + arg1 + to_add + df From 50fc0ee6aad19be8d51a1e8ccdab4fc25659fd92 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Fri, 16 Oct 2020 14:14:22 +0300 Subject: [PATCH 10/10] restart checks