Skip to content

Commit f611e26

Browse files
author
MomIsBestFriend
committed
Merge remote-tracking branch 'upstream/master' into CI-unify-boilerplate
2 parents 2e249a8 + c5948d1 commit f611e26

37 files changed

+295
-499
lines changed

doc/source/user_guide/text.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ l. For ``StringDtype``, :ref:`string accessor methods<api.series.str>`
8787

8888
.. ipython:: python
8989
90-
s.astype(object).str.count("a")
91-
s.astype(object).dropna().str.count("a")
90+
s2 = pd.Series(["a", None, "b"], dtype="object")
91+
s2.str.count("a")
92+
s2.dropna().str.count("a")
9293
9394
When NA values are present, the output dtype is float64. Similarly for
9495
methods returning boolean values.

doc/source/whatsnew/v1.0.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ Reshaping
10041004
Sparse
10051005
^^^^^^
10061006
- Bug in :class:`SparseDataFrame` arithmetic operations incorrectly casting inputs to float (:issue:`28107`)
1007-
-
1007+
- Bug in ``DataFrame.sparse`` returning a ``Series`` when there was a column named ``sparse`` rather than the accessor (:issue:`30758`)
10081008
-
10091009

10101010
ExtensionArray

pandas/_testing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ def assert_frame_equal(
12871287
>>> assert_frame_equal(df1, df2)
12881288
Traceback (most recent call last):
12891289
...
1290-
AssertionError: Attributes of DataFrame.iloc[:, 1] are different
1290+
AssertionError: Attributes of DataFrame.iloc[:, 1] (column name="b") are different
12911291
12921292
Attribute "dtype" are different
12931293
[left]: int64
@@ -1366,7 +1366,7 @@ def assert_frame_equal(
13661366
check_names=check_names,
13671367
check_datetimelike_compat=check_datetimelike_compat,
13681368
check_categorical=check_categorical,
1369-
obj=f"{obj}.iloc[:, {i}]",
1369+
obj=f'{obj}.iloc[:, {i}] (column name="{col}")',
13701370
)
13711371

13721372

pandas/core/arrays/datetimelike.py

+81-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from pandas._libs.tslibs.timedeltas import Timedelta, delta_to_nanoseconds
1212
from pandas._libs.tslibs.timestamps import RoundTo, round_nsint64
1313
from pandas._typing import DatetimeLikeScalar
14+
from pandas.compat import set_function_name
1415
from pandas.compat.numpy import function as nv
1516
from pandas.errors import AbstractMethodError, NullFrequencyError, PerformanceWarning
1617
from pandas.util._decorators import Appender, Substitution
@@ -37,19 +38,94 @@
3738
from pandas.core.dtypes.inference import is_array_like
3839
from pandas.core.dtypes.missing import is_valid_nat_for_dtype, isna
3940

40-
from pandas.core import missing, nanops
41+
from pandas.core import missing, nanops, ops
4142
from pandas.core.algorithms import checked_add_with_arr, take, unique1d, value_counts
4243
import pandas.core.common as com
4344
from pandas.core.indexers import check_bool_array_indexer
4445
from pandas.core.ops.common import unpack_zerodim_and_defer
45-
from pandas.core.ops.invalid import make_invalid_op
46+
from pandas.core.ops.invalid import invalid_comparison, make_invalid_op
4647

4748
from pandas.tseries import frequencies
4849
from pandas.tseries.offsets import DateOffset, Tick
4950

5051
from .base import ExtensionArray, ExtensionOpsMixin
5152

5253

54+
def _datetimelike_array_cmp(cls, op):
55+
"""
56+
Wrap comparison operations to convert Timestamp/Timedelta/Period-like to
57+
boxed scalars/arrays.
58+
"""
59+
opname = f"__{op.__name__}__"
60+
nat_result = opname == "__ne__"
61+
62+
@unpack_zerodim_and_defer(opname)
63+
def wrapper(self, other):
64+
65+
if isinstance(other, str):
66+
try:
67+
# GH#18435 strings get a pass from tzawareness compat
68+
other = self._scalar_from_string(other)
69+
except ValueError:
70+
# failed to parse as Timestamp/Timedelta/Period
71+
return invalid_comparison(self, other, op)
72+
73+
if isinstance(other, self._recognized_scalars) or other is NaT:
74+
other = self._scalar_type(other)
75+
self._check_compatible_with(other)
76+
77+
other_i8 = self._unbox_scalar(other)
78+
79+
result = op(self.view("i8"), other_i8)
80+
if isna(other):
81+
result.fill(nat_result)
82+
83+
elif not is_list_like(other):
84+
return invalid_comparison(self, other, op)
85+
86+
elif len(other) != len(self):
87+
raise ValueError("Lengths must match")
88+
89+
else:
90+
if isinstance(other, list):
91+
# TODO: could use pd.Index to do inference?
92+
other = np.array(other)
93+
94+
if not isinstance(other, (np.ndarray, type(self))):
95+
return invalid_comparison(self, other, op)
96+
97+
if is_object_dtype(other):
98+
# We have to use comp_method_OBJECT_ARRAY instead of numpy
99+
# comparison otherwise it would fail to raise when
100+
# comparing tz-aware and tz-naive
101+
with np.errstate(all="ignore"):
102+
result = ops.comp_method_OBJECT_ARRAY(
103+
op, self.astype(object), other
104+
)
105+
o_mask = isna(other)
106+
107+
elif not type(self)._is_recognized_dtype(other.dtype):
108+
return invalid_comparison(self, other, op)
109+
110+
else:
111+
# For PeriodDType this casting is unnecessary
112+
other = type(self)._from_sequence(other)
113+
self._check_compatible_with(other)
114+
115+
result = op(self.view("i8"), other.view("i8"))
116+
o_mask = other._isnan
117+
118+
if o_mask.any():
119+
result[o_mask] = nat_result
120+
121+
if self._hasnans:
122+
result[self._isnan] = nat_result
123+
124+
return result
125+
126+
return set_function_name(wrapper, opname, cls)
127+
128+
53129
class AttributesMixin:
54130
_data: np.ndarray
55131

@@ -934,6 +1010,7 @@ def _is_unique(self):
9341010

9351011
# ------------------------------------------------------------------
9361012
# Arithmetic Methods
1013+
_create_comparison_method = classmethod(_datetimelike_array_cmp)
9371014

9381015
# pow is invalid for all three subclasses; TimedeltaArray will override
9391016
# the multiplication and division ops
@@ -1485,6 +1562,8 @@ def mean(self, skipna=True):
14851562
return self._box_func(result)
14861563

14871564

1565+
DatetimeLikeArrayMixin._add_comparison_ops()
1566+
14881567
# -------------------------------------------------------------------
14891568
# Shared Constructor Helpers
14901569

pandas/core/arrays/datetimes.py

+1-86
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
timezones,
1919
tzconversion,
2020
)
21-
import pandas.compat as compat
2221
from pandas.errors import PerformanceWarning
2322

2423
from pandas.core.dtypes.common import (
@@ -32,7 +31,6 @@
3231
is_dtype_equal,
3332
is_extension_array_dtype,
3433
is_float_dtype,
35-
is_list_like,
3634
is_object_dtype,
3735
is_period_dtype,
3836
is_string_dtype,
@@ -43,13 +41,10 @@
4341
from pandas.core.dtypes.generic import ABCIndexClass, ABCPandasArray, ABCSeries
4442
from pandas.core.dtypes.missing import isna
4543

46-
from pandas.core import ops
4744
from pandas.core.algorithms import checked_add_with_arr
4845
from pandas.core.arrays import datetimelike as dtl
4946
from pandas.core.arrays._ranges import generate_regular_range
5047
import pandas.core.common as com
51-
from pandas.core.ops.common import unpack_zerodim_and_defer
52-
from pandas.core.ops.invalid import invalid_comparison
5348

5449
from pandas.tseries.frequencies import get_period_alias, to_offset
5550
from pandas.tseries.offsets import Day, Tick
@@ -131,81 +126,6 @@ def f(self):
131126
return property(f)
132127

133128

134-
def _dt_array_cmp(cls, op):
135-
"""
136-
Wrap comparison operations to convert datetime-like to datetime64
137-
"""
138-
opname = f"__{op.__name__}__"
139-
nat_result = opname == "__ne__"
140-
141-
@unpack_zerodim_and_defer(opname)
142-
def wrapper(self, other):
143-
144-
if isinstance(other, str):
145-
try:
146-
# GH#18435 strings get a pass from tzawareness compat
147-
other = self._scalar_from_string(other)
148-
except ValueError:
149-
# string that cannot be parsed to Timestamp
150-
return invalid_comparison(self, other, op)
151-
152-
if isinstance(other, self._recognized_scalars) or other is NaT:
153-
other = self._scalar_type(other)
154-
self._assert_tzawareness_compat(other)
155-
156-
other_i8 = other.value
157-
158-
result = op(self.view("i8"), other_i8)
159-
if isna(other):
160-
result.fill(nat_result)
161-
162-
elif not is_list_like(other):
163-
return invalid_comparison(self, other, op)
164-
165-
elif len(other) != len(self):
166-
raise ValueError("Lengths must match")
167-
168-
else:
169-
if isinstance(other, list):
170-
other = np.array(other)
171-
172-
if not isinstance(other, (np.ndarray, cls)):
173-
# Following Timestamp convention, __eq__ is all-False
174-
# and __ne__ is all True, others raise TypeError.
175-
return invalid_comparison(self, other, op)
176-
177-
if is_object_dtype(other):
178-
# We have to use comp_method_OBJECT_ARRAY instead of numpy
179-
# comparison otherwise it would fail to raise when
180-
# comparing tz-aware and tz-naive
181-
with np.errstate(all="ignore"):
182-
result = ops.comp_method_OBJECT_ARRAY(
183-
op, self.astype(object), other
184-
)
185-
o_mask = isna(other)
186-
187-
elif not cls._is_recognized_dtype(other.dtype):
188-
# e.g. is_timedelta64_dtype(other)
189-
return invalid_comparison(self, other, op)
190-
191-
else:
192-
self._assert_tzawareness_compat(other)
193-
other = type(self)._from_sequence(other)
194-
195-
result = op(self.view("i8"), other.view("i8"))
196-
o_mask = other._isnan
197-
198-
if o_mask.any():
199-
result[o_mask] = nat_result
200-
201-
if self._hasnans:
202-
result[self._isnan] = nat_result
203-
204-
return result
205-
206-
return compat.set_function_name(wrapper, opname, cls)
207-
208-
209129
class DatetimeArray(dtl.DatetimeLikeArrayMixin, dtl.TimelikeOps, dtl.DatelikeOps):
210130
"""
211131
Pandas ExtensionArray for tz-naive or tz-aware datetime data.
@@ -324,7 +244,7 @@ def __init__(self, values, dtype=_NS_DTYPE, freq=None, copy=False):
324244
raise TypeError(msg)
325245
elif values.tz:
326246
dtype = values.dtype
327-
# freq = validate_values_freq(values, freq)
247+
328248
if freq is None:
329249
freq = values.freq
330250
values = values._data
@@ -714,8 +634,6 @@ def _format_native_types(self, na_rep="NaT", date_format=None, **kwargs):
714634
# -----------------------------------------------------------------
715635
# Comparison Methods
716636

717-
_create_comparison_method = classmethod(_dt_array_cmp)
718-
719637
def _has_same_tz(self, other):
720638
zzone = self._timezone
721639

@@ -1767,9 +1685,6 @@ def to_julian_date(self):
17671685
)
17681686

17691687

1770-
DatetimeArray._add_comparison_ops()
1771-
1772-
17731688
# -------------------------------------------------------------------
17741689
# Constructor Helpers
17751690

0 commit comments

Comments
 (0)