Skip to content

Commit 96c8ad8

Browse files
committed
CLN: resolve merge conflict in whatsnew
2 parents bcc770b + 0badf06 commit 96c8ad8

File tree

21 files changed

+239
-84
lines changed

21 files changed

+239
-84
lines changed

ci/code_checks.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function invgrep {
3939
}
4040

4141
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
42-
FLAKE8_FORMAT="##[error]%(path)s:%(row)s:%(col)s:%(code):%(text)s"
42+
FLAKE8_FORMAT="##[error]%(path)s:%(row)s:%(col)s:%(code)s:%(text)s"
4343
INVGREP_PREPEND="##[error]"
4444
else
4545
FLAKE8_FORMAT="default"

doc/source/user_guide/io.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The pandas I/O API is a set of top level ``reader`` functions accessed like
3535
binary;`SPSS <https://en.wikipedia.org/wiki/SPSS>`__;:ref:`read_spss<io.spss_reader>`;
3636
binary;`Python Pickle Format <https://docs.python.org/3/library/pickle.html>`__;:ref:`read_pickle<io.pickle>`;:ref:`to_pickle<io.pickle>`
3737
SQL;`SQL <https://en.wikipedia.org/wiki/SQL>`__;:ref:`read_sql<io.sql>`;:ref:`to_sql<io.sql>`
38-
SQL;`Google Big Query <https://en.wikipedia.org/wiki/BigQuery>`__;:ref:`read_gbq<io.bigquery>`;:ref:`to_gbq<io.bigquery>`
38+
SQL;`Google BigQuery <https://en.wikipedia.org/wiki/BigQuery>`__;:ref:`read_gbq<io.bigquery>`;:ref:`to_gbq<io.bigquery>`
3939

4040
:ref:`Here <io.perf>` is an informal performance comparison for some of these IO methods.
4141

doc/source/user_guide/text.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ l. For ``StringDtype``, :ref:`string accessor methods<api.series.str>`
9494
2. Some string methods, like :meth:`Series.str.decode` are not available
9595
on ``StringArray`` because ``StringArray`` only holds strings, not
9696
bytes.
97-
97+
3. In comparision operations, :class:`arrays.StringArray` and ``Series`` backed
98+
by a ``StringArray`` will return an object with :class:`BooleanDtype`,
99+
rather than a ``bool`` dtype object. Missing values in a ``StringArray``
100+
will propagate in comparision operations, rather than always comparing
101+
unequal like :attr:`numpy.nan`.
98102

99103
Everything else that follows in the rest of this document applies equally to
100104
``string`` and ``object`` dtype.

doc/source/whatsnew/v1.0.0.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ Documentation Improvements
486486
Deprecations
487487
~~~~~~~~~~~~
488488

489+
- :meth:`Series.item` and :meth:`Index.item` have been _undeprecated_ (:issue:`29250`)
489490
- ``Index.set_value`` has been deprecated. For a given index ``idx``, array ``arr``,
490491
value in ``idx`` of ``idx_val`` and a new value of ``val``, ``idx.set_value(arr, idx_val, val)``
491492
is equivalent to ``arr[idx.get_loc(idx_val)] = val``, which should be used instead (:issue:`28621`).
@@ -681,6 +682,7 @@ Categorical
681682
same type as if one used the :meth:`.str.` / :meth:`.dt.` on a :class:`Series` of that type. E.g. when accessing :meth:`Series.dt.tz_localize` on a
682683
:class:`Categorical` with duplicate entries, the accessor was skipping duplicates (:issue:`27952`)
683684
- Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` that would give incorrect results on categorical data (:issue:`26988`)
685+
- Bug where calling :meth:`Categorical.min` or :meth:`Categorical.max` on an empty Categorical would raise a numpy exception (:issue:`30227`)
684686

685687

686688
Datetimelike
@@ -703,6 +705,8 @@ Datetimelike
703705
- Bug in :func:`pandas.to_datetime` when called with ``None`` raising ``TypeError`` instead of returning ``NaT`` (:issue:`30011`)
704706
- Bug in :func:`pandas.to_datetime` failing for `deques` when using ``cache=True`` (the default) (:issue:`29403`)
705707
- Bug in :func:`pandas.to_datetime` when called with ``Series`` storing ``IntegerArray`` raising ``TypeError`` instead of returning ``Series`` (:issue:`30050`)
708+
- Bug in :meth:`Series.item` with ``datetime64`` or ``timedelta64`` dtype, :meth:`DatetimeIndex.item`, and :meth:`TimedeltaIndex.item` returning an integer instead of a :class:`Timestamp` or :class:`Timedelta` (:issue:`30175`)
709+
-
706710

707711
Timedelta
708712
^^^^^^^^^
@@ -863,7 +867,7 @@ ExtensionArray
863867

864868
- Bug in :class:`arrays.PandasArray` when setting a scalar string (:issue:`28118`, :issue:`28150`).
865869
- Bug where nullable integers could not be compared to strings (:issue:`28930`)
866-
-
870+
- Bug where :class:`DataFrame` constructor raised ValueError with list-like data and ``dtype`` specified (:issue:`30280`)
867871

868872

869873
Other

pandas/_config/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ def register_option(key: str, defval: object, doc="", validator=None, cb=None):
462462

463463
cursor = _global_config
464464
msg = "Path prefix to option '{option}' is already an option"
465+
465466
for i, p in enumerate(path[:-1]):
466467
if not isinstance(cursor, dict):
467468
raise OptionError(msg.format(option=".".join(path[:i])))
@@ -650,8 +651,9 @@ def _build_option_description(k):
650651
s += f"\n [default: {o.defval}] [currently: {_get_option(k, True)}]"
651652

652653
if d:
654+
rkey = d.rkey if d.rkey else ""
653655
s += "\n (Deprecated"
654-
s += ", use `{rkey}` instead.".format(rkey=d.rkey if d.rkey else "")
656+
s += f", use `{rkey}` instead."
655657
s += ")"
656658

657659
return s

pandas/_config/localization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,6 @@ def get_locales(prefix=None, normalize=True, locale_getter=_default_locale_gette
161161
if prefix is None:
162162
return _valid_locales(out_locales, normalize)
163163

164-
pattern = re.compile("{prefix}.*".format(prefix=prefix))
164+
pattern = re.compile(f"{prefix}.*")
165165
found = pattern.findall("\n".join(out_locales))
166166
return _valid_locales(found, normalize)

pandas/core/arrays/base.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
from pandas.core.missing import backfill_1d, pad_1d
2828
from pandas.core.sorting import nargsort
2929

30-
_not_implemented_message = "{} does not implement {}."
31-
3230
_extension_array_shared_docs: Dict[str, str] = dict()
3331

3432

@@ -330,9 +328,7 @@ def __setitem__(self, key: Union[int, np.ndarray], value: Any) -> None:
330328
# __init__ method coerces that value, then so should __setitem__
331329
# Note, also, that Series/DataFrame.where internally use __setitem__
332330
# on a copy of the data.
333-
raise NotImplementedError(
334-
_not_implemented_message.format(type(self), "__setitem__")
335-
)
331+
raise NotImplementedError(f"{type(self)} does not implement __setitem__.")
336332

337333
def __len__(self) -> int:
338334
"""

pandas/core/arrays/categorical.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,10 @@ def min(self, skipna=True):
21152115
21162116
Only ordered `Categoricals` have a minimum!
21172117
2118+
.. versionchanged:: 1.0.0
2119+
2120+
Returns an NA value on empty arrays
2121+
21182122
Raises
21192123
------
21202124
TypeError
@@ -2125,6 +2129,10 @@ def min(self, skipna=True):
21252129
min : the minimum of this `Categorical`
21262130
"""
21272131
self.check_for_ordered("min")
2132+
2133+
if not len(self._codes):
2134+
return self.dtype.na_value
2135+
21282136
good = self._codes != -1
21292137
if not good.all():
21302138
if skipna:
@@ -2142,6 +2150,10 @@ def max(self, skipna=True):
21422150
21432151
Only ordered `Categoricals` have a maximum!
21442152
2153+
.. versionchanged:: 1.0.0
2154+
2155+
Returns an NA value on empty arrays
2156+
21452157
Raises
21462158
------
21472159
TypeError
@@ -2152,6 +2164,10 @@ def max(self, skipna=True):
21522164
max : the maximum of this `Categorical`
21532165
"""
21542166
self.check_for_ordered("max")
2167+
2168+
if not len(self._codes):
2169+
return self.dtype.na_value
2170+
21552171
good = self._codes != -1
21562172
if not good.all():
21572173
if skipna:

pandas/core/arrays/string_.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class StringArray(PandasArray):
134134
The string methods are available on Series backed by
135135
a StringArray.
136136
137+
Notes
138+
-----
139+
StringArray returns a BooleanArray for comparison methods.
140+
137141
Examples
138142
--------
139143
>>> pd.array(['This is', 'some text', None, 'data.'], dtype="string")
@@ -148,6 +152,13 @@ class StringArray(PandasArray):
148152
Traceback (most recent call last):
149153
...
150154
ValueError: StringArray requires an object-dtype ndarray of strings.
155+
156+
For comparision methods, this returns a :class:`pandas.BooleanArray`
157+
158+
>>> pd.array(["a", None, "c"], dtype="string") == "a"
159+
<BooleanArray>
160+
[True, NA, False]
161+
Length: 3, dtype: boolean
151162
"""
152163

153164
# undo the PandasArray hack
@@ -255,7 +266,12 @@ def value_counts(self, dropna=False):
255266
# Overrride parent because we have different return types.
256267
@classmethod
257268
def _create_arithmetic_method(cls, op):
269+
# Note: this handles both arithmetic and comparison methods.
258270
def method(self, other):
271+
from pandas.arrays import BooleanArray
272+
273+
assert op.__name__ in ops.ARITHMETIC_BINOPS | ops.COMPARISON_BINOPS
274+
259275
if isinstance(other, (ABCIndexClass, ABCSeries, ABCDataFrame)):
260276
return NotImplemented
261277

@@ -275,15 +291,16 @@ def method(self, other):
275291
other = np.asarray(other)
276292
other = other[valid]
277293

278-
result = np.empty_like(self._ndarray, dtype="object")
279-
result[mask] = StringDtype.na_value
280-
result[valid] = op(self._ndarray[valid], other)
281-
282-
if op.__name__ in {"add", "radd", "mul", "rmul"}:
294+
if op.__name__ in ops.ARITHMETIC_BINOPS:
295+
result = np.empty_like(self._ndarray, dtype="object")
296+
result[mask] = StringDtype.na_value
297+
result[valid] = op(self._ndarray[valid], other)
283298
return StringArray(result)
284299
else:
285-
dtype = "object" if mask.any() else "bool"
286-
return np.asarray(result, dtype=dtype)
300+
# logical
301+
result = np.zeros(len(self._ndarray), dtype="bool")
302+
result[valid] = op(self._ndarray[valid], other)
303+
return BooleanArray(result, mask)
287304

288305
return compat.set_function_name(method, f"__{op.__name__}__", cls)
289306

pandas/core/base.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from collections import OrderedDict
66
import textwrap
77
from typing import Dict, FrozenSet, List, Optional
8-
import warnings
98

109
import numpy as np
1110

@@ -26,6 +25,7 @@
2625
is_object_dtype,
2726
is_scalar,
2827
is_timedelta64_ns_dtype,
28+
needs_i8_conversion,
2929
)
3030
from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries
3131
from pandas.core.dtypes.missing import isna
@@ -659,19 +659,27 @@ def item(self):
659659
"""
660660
Return the first element of the underlying data as a python scalar.
661661
662-
.. deprecated:: 0.25.0
663-
664662
Returns
665663
-------
666664
scalar
667665
The first element of %(klass)s.
666+
667+
Raises
668+
------
669+
ValueError
670+
If the data is not length-1.
668671
"""
669-
warnings.warn(
670-
"`item` has been deprecated and will be removed in a future version",
671-
FutureWarning,
672-
stacklevel=2,
673-
)
674-
return self.values.item()
672+
if not (
673+
is_extension_array_dtype(self.dtype) or needs_i8_conversion(self.dtype)
674+
):
675+
# numpy returns ints instead of datetime64/timedelta64 objects,
676+
# which we need to wrap in Timestamp/Timedelta/Period regardless.
677+
return self.values.item()
678+
679+
if len(self) == 1:
680+
return next(iter(self))
681+
else:
682+
raise ValueError("can only convert an array of size 1 to a Python scalar")
675683

676684
@property
677685
def nbytes(self):

pandas/core/indexes/period.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import datetime, timedelta
2-
import warnings
32
import weakref
43

54
import numpy as np
@@ -862,27 +861,6 @@ def __setstate__(self, state):
862861

863862
_unpickle_compat = __setstate__
864863

865-
def item(self):
866-
"""
867-
Return the first element of the underlying data as a python
868-
scalar
869-
870-
.. deprecated:: 0.25.0
871-
872-
"""
873-
warnings.warn(
874-
"`item` has been deprecated and will be removed in a future version",
875-
FutureWarning,
876-
stacklevel=2,
877-
)
878-
# TODO(DatetimeArray): remove
879-
if len(self) == 1:
880-
return self[0]
881-
else:
882-
# TODO: is this still necessary?
883-
# copy numpy's message here because Py26 raises an IndexError
884-
raise ValueError("can only convert an array of size 1 to a Python scalar")
885-
886864
def memory_usage(self, deep=False):
887865
result = super().memory_usage(deep=deep)
888866
if hasattr(self, "_cache") and "_int64index" in self._cache:

pandas/core/internals/construction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def init_ndarray(values, index, columns, dtype=None, copy=False):
150150

151151
index, columns = _get_axes(len(values), 1, index, columns)
152152
return arrays_to_mgr([values], columns, index, columns, dtype=dtype)
153-
elif is_extension_array_dtype(values):
153+
elif is_extension_array_dtype(values) or is_extension_array_dtype(dtype):
154154
# GH#19157
155155
if columns is None:
156156
columns = [0]

pandas/core/ops/__init__.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"""
66
import datetime
77
import operator
8-
from typing import Tuple, Union
8+
from typing import Set, Tuple, Union
99

1010
import numpy as np
1111

@@ -59,6 +59,37 @@
5959
rxor,
6060
)
6161

62+
# -----------------------------------------------------------------------------
63+
# constants
64+
ARITHMETIC_BINOPS: Set[str] = {
65+
"add",
66+
"sub",
67+
"mul",
68+
"pow",
69+
"mod",
70+
"floordiv",
71+
"truediv",
72+
"divmod",
73+
"radd",
74+
"rsub",
75+
"rmul",
76+
"rpow",
77+
"rmod",
78+
"rfloordiv",
79+
"rtruediv",
80+
"rdivmod",
81+
}
82+
83+
84+
COMPARISON_BINOPS: Set[str] = {
85+
"eq",
86+
"ne",
87+
"lt",
88+
"gt",
89+
"le",
90+
"ge",
91+
}
92+
6293
# -----------------------------------------------------------------------------
6394
# Ops Wrapping Utilities
6495

0 commit comments

Comments
 (0)