Skip to content

Commit 8d052ad

Browse files
feedback: docs, whatsnew, dataframe test, strict dtype test
1 parent aae2f94 commit 8d052ad

File tree

7 files changed

+38
-12
lines changed

7 files changed

+38
-12
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Other enhancements
150150
such as ``dict`` and ``list``, mirroring the behavior of :meth:`DataFrame.update` (:issue:`33215`)
151151
- :meth:`~pandas.core.groupby.GroupBy.transform` and :meth:`~pandas.core.groupby.GroupBy.aggregate` has gained ``engine`` and ``engine_kwargs`` arguments that supports executing functions with ``Numba`` (:issue:`32854`, :issue:`33388`)
152152
- :meth:`~pandas.core.resample.Resampler.interpolate` now supports SciPy interpolation method :class:`scipy.interpolate.CubicSpline` as method ``cubicspline`` (:issue:`33670`)
153+
- The ``ExtensionArray`` class has now an ``equals`` method, similarly to ``Series.equals()`` (:issue:`27081`).
153154
-
154155

155156
.. ---------------------------------------------------------------------------

pandas/_testing.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1490,7 +1490,9 @@ def box_expected(expected, box_cls, transpose=True):
14901490
-------
14911491
subclass of box_cls
14921492
"""
1493-
if box_cls is pd.Index:
1493+
if box_cls is pd.array:
1494+
expected = pd.array(expected)
1495+
elif box_cls is pd.Index:
14941496
expected = pd.Index(expected)
14951497
elif box_cls is pd.Series:
14961498
expected = pd.Series(expected)

pandas/core/arrays/base.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,19 @@ def __iter__(self):
335335
for i in range(len(self)):
336336
yield self[i]
337337

338-
def __eq__(self, other: Any) -> Union[np.ndarray, "ExtensionArray"]:
338+
def __eq__(self, other: Any) -> ArrayLike:
339339
"""
340340
Return for `self == other` (element-wise equality).
341341
"""
342+
# Implementer note: this should return a boolean numpy ndarray or
343+
# a boolean ExtensionArray.
344+
# When `other` is one of Series, Index, or DataFrame, this method should
345+
# return NotImplemented (to ensure that those objects are responsible for
346+
# first unpacking the arrays, and then dispatch the operation to the
347+
# underlying arrays)
342348
raise AbstractMethodError(self)
343349

344-
def __ne__(self, other: Any) -> Union[np.ndarray, "ExtensionArray"]:
350+
def __ne__(self, other: Any) -> ArrayLike:
345351
"""
346352
Return for `self != other` (element-wise in-equality).
347353
"""
@@ -713,6 +719,8 @@ def equals(self, other: "ExtensionArray") -> bool:
713719
"""
714720
if not type(self) == type(other):
715721
return False
722+
elif not self.dtype == other.dtype:
723+
return False
716724
elif not len(self) == len(other):
717725
return False
718726
else:

pandas/tests/arrays/integer/test_comparison.py

+10
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,13 @@ def test_compare_to_int(self, any_nullable_int_dtype, all_compare_operators):
104104
expected[s2.isna()] = pd.NA
105105

106106
self.assert_series_equal(result, expected)
107+
108+
109+
def test_equals():
110+
# GH-30652
111+
# equals is generally tested in /tests/extension/base/methods, but this
112+
# specifically tests that two arrays of the same class but different dtype
113+
# do not evaluate equal
114+
a1 = pd.array([1, 2, None], dtype="Int64")
115+
a2 = pd.array([1, 2, None], dtype="Int32")
116+
assert a1.equals(a2) is False

pandas/tests/extension/base/methods.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -422,14 +422,17 @@ def test_repeat_raises(self, data, repeats, kwargs, error, msg, use_numpy):
422422
else:
423423
data.repeat(repeats, **kwargs)
424424

425-
def test_equals(self, data, na_value, as_series):
425+
@pytest.mark.parametrize("box", [pd.array, pd.Series, pd.DataFrame])
426+
def test_equals(self, data, na_value, as_series, box):
426427
data2 = type(data)._from_sequence([data[0]] * len(data), dtype=data.dtype)
427428
data_na = type(data)._from_sequence([na_value] * len(data), dtype=data.dtype)
428429

429-
if as_series:
430-
data = pd.Series(data)
431-
data2 = pd.Series(data2)
432-
data_na = pd.Series(data_na)
430+
data = tm.box_expected(data, box, transpose=False)
431+
data2 = tm.box_expected(data2, box, transpose=False)
432+
data_na = tm.box_expected(data_na, box, transpose=False)
433+
434+
# we are asserting with `is True/False` explicitly, to test that the
435+
# result is an actual Python bool, and not something "truthy"
433436

434437
assert data.equals(data) is True
435438
assert data.equals(data.copy()) is True

pandas/tests/extension/test_numpy.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,10 @@ def test_diff(self, data, periods):
262262
return super().test_diff(data, periods)
263263

264264
@skip_nested
265-
def test_equals(self, data, na_value, as_series):
265+
@pytest.mark.parametrize("box", [pd.array, pd.Series, pd.DataFrame])
266+
def test_equals(self, data, na_value, as_series, box):
266267
# Fails creating with _from_sequence
267-
super().test_equals(data, na_value, as_series)
268+
super().test_equals(data, na_value, as_series, box)
268269

269270

270271
@skip_nested

pandas/tests/extension/test_sparse.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,10 @@ def test_shift_0_periods(self, data):
316316
data._sparse_values[0] = data._sparse_values[1]
317317
assert result._sparse_values[0] != result._sparse_values[1]
318318

319-
def test_equals(self, data, na_value, as_series):
319+
@pytest.mark.parametrize("box", [pd.array, pd.Series, pd.DataFrame])
320+
def test_equals(self, data, na_value, as_series, box):
320321
self._check_unsupported(data)
321-
super().test_equals(data, na_value, as_series)
322+
super().test_equals(data, na_value, as_series, box)
322323

323324

324325
class TestCasting(BaseSparseTests, base.BaseCastingTests):

0 commit comments

Comments
 (0)