Skip to content

Commit a22cf43

Browse files
BUG: Enable Series.equals to compare numpy arrays to scalars (#36161)
1 parent c1484b1 commit a22cf43

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ Numeric
270270
^^^^^^^
271271
- Bug in :func:`to_numeric` where float precision was incorrect (:issue:`31364`)
272272
- Bug in :meth:`DataFrame.any` with ``axis=1`` and ``bool_only=True`` ignoring the ``bool_only`` keyword (:issue:`32432`)
273+
- Bug in :meth:`Series.equals` where a ``ValueError`` was raised when numpy arrays were compared to scalars (:issue:`35267`)
273274
-
274275

275276
Conversion

pandas/_libs/lib.pyx

+10-1
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,16 @@ def array_equivalent_object(left: object[:], right: object[:]) -> bool:
591591
if "tz-naive and tz-aware" in str(err):
592592
return False
593593
raise
594-
594+
except ValueError:
595+
# Avoid raising ValueError when comparing Numpy arrays to other types
596+
if cnp.PyArray_IsAnyScalar(x) != cnp.PyArray_IsAnyScalar(y):
597+
# Only compare scalars to scalars and non-scalars to non-scalars
598+
return False
599+
elif (not (cnp.PyArray_IsPythonScalar(x) or cnp.PyArray_IsPythonScalar(y))
600+
and not (isinstance(x, type(y)) or isinstance(y, type(x)))):
601+
# Check if non-scalars have the same type
602+
return False
603+
raise
595604
return True
596605

597606

pandas/tests/dtypes/test_missing.py

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from contextlib import nullcontext
12
from datetime import datetime
23
from decimal import Decimal
34

@@ -383,6 +384,20 @@ def test_array_equivalent(dtype_equal):
383384
assert not array_equivalent(DatetimeIndex([0, np.nan]), TimedeltaIndex([0, np.nan]))
384385

385386

387+
@pytest.mark.parametrize(
388+
"val", [1, 1.1, 1 + 1j, True, "abc", [1, 2], (1, 2), {1, 2}, {"a": 1}, None]
389+
)
390+
def test_array_equivalent_series(val):
391+
arr = np.array([1, 2])
392+
cm = (
393+
tm.assert_produces_warning(FutureWarning, check_stacklevel=False)
394+
if isinstance(val, str)
395+
else nullcontext()
396+
)
397+
with cm:
398+
assert not array_equivalent(Series([arr, arr]), Series([arr, val]))
399+
400+
386401
def test_array_equivalent_different_dtype_but_equal():
387402
# Unclear if this is exposed anywhere in the public-facing API
388403
assert array_equivalent(np.array([1, 2]), np.array([1.0, 2.0]))

pandas/tests/series/methods/test_equals.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
from contextlib import nullcontext
2+
13
import numpy as np
24
import pytest
35

46
from pandas import MultiIndex, Series
7+
import pandas._testing as tm
58

69

710
@pytest.mark.parametrize(
@@ -24,16 +27,25 @@ def test_equals(arr, idx):
2427
assert not s1.equals(s2)
2528

2629

27-
def test_equals_list_array():
30+
@pytest.mark.parametrize(
31+
"val", [1, 1.1, 1 + 1j, True, "abc", [1, 2], (1, 2), {1, 2}, {"a": 1}, None]
32+
)
33+
def test_equals_list_array(val):
2834
# GH20676 Verify equals operator for list of Numpy arrays
2935
arr = np.array([1, 2])
3036
s1 = Series([arr, arr])
3137
s2 = s1.copy()
3238
assert s1.equals(s2)
3339

34-
# TODO: Series equals should also work between single value and list
35-
# s1[1] = 9
36-
# assert not s1.equals(s2)
40+
s1[1] = val
41+
42+
cm = (
43+
tm.assert_produces_warning(FutureWarning, check_stacklevel=False)
44+
if isinstance(val, str)
45+
else nullcontext()
46+
)
47+
with cm:
48+
assert not s1.equals(s2)
3749

3850

3951
def test_equals_false_negative():

0 commit comments

Comments
 (0)