Skip to content

Commit 49ddb56

Browse files
authored
Merge pull request #251 from pandas-dev/master
Sync Fork from Upstream Repo
2 parents 56d48e6 + 226876a commit 49ddb56

19 files changed

+220
-44
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ repos:
110110
entry: python scripts/generate_pip_deps_from_conda.py
111111
files: ^(environment.yml|requirements-dev.txt)$
112112
pass_filenames: false
113-
additional_dependencies: [pyyaml]
113+
additional_dependencies: [pyyaml, toml]
114114
- id: sync-flake8-versions
115115
name: Check flake8 version is synced across flake8, yesqa, and environment.yml
116116
language: python

doc/source/development/contributing_environment.rst

+2-5
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,8 @@ Creating a Python environment (pip)
189189
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190190

191191
If you aren't using conda for your development environment, follow these instructions.
192-
You'll need to have at least the :ref:`minimum Python version <install.version>` that pandas supports. If your Python version
193-
is 3.8.0 (or later), you might need to update your ``setuptools`` to version 42.0.0 (or later)
194-
in your development environment before installing the build dependencies::
195-
196-
pip install --upgrade setuptools
192+
You'll need to have at least the :ref:`minimum Python version <install.version>` that pandas supports.
193+
You also need to have ``setuptools`` 51.0.0 or later to build pandas.
197194

198195
**Unix**/**macOS with virtualenv**
199196

doc/source/whatsnew/v1.3.2.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Fixed regressions
2222
- Regression in :meth:`DataFrame.drop` does nothing if :class:`MultiIndex` has duplicates and indexer is a tuple or list of tuples (:issue:`42771`)
2323
- Fixed regression where :meth:`pandas.read_csv` raised a ``ValueError`` when parameters ``names`` and ``prefix`` were both set to None (:issue:`42387`)
2424
- Fixed regression in comparisons between :class:`Timestamp` object and ``datetime64`` objects outside the implementation bounds for nanosecond ``datetime64`` (:issue:`42794`)
25-
-
25+
- Fixed regression in :meth:`.Styler.highlight_min` and :meth:`.Styler.highlight_max` where ``pandas.NA`` was not successfully ignored (:issue:`42650`)
2626

2727
.. ---------------------------------------------------------------------------
2828
@@ -31,7 +31,7 @@ Fixed regressions
3131
Bug fixes
3232
~~~~~~~~~
3333
- 1D slices over extension types turn into N-dimensional slices over ExtensionArrays (:issue:`42430`)
34-
-
34+
- :meth:`.Styler.hide_columns` now hides the index name header row as well as column headers (:issue:`42101`)
3535

3636
.. ---------------------------------------------------------------------------
3737

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ Groupby/resample/rolling
270270
- Bug in :meth:`Series.rolling.apply`, :meth:`DataFrame.rolling.apply`, :meth:`Series.expanding.apply` and :meth:`DataFrame.expanding.apply` with ``engine="numba"`` where ``*args`` were being cached with the user passed function (:issue:`42287`)
271271
- Bug in :meth:`DataFrame.groupby.rolling.var` would calculate the rolling variance only on the first group (:issue:`42442`)
272272
- Bug in :meth:`GroupBy.shift` that would return the grouping columns if ``fill_value`` was not None (:issue:`41556`)
273+
- Bug in :meth:`pandas.DataFrame.ewm`, where non-float64 dtypes were silently failing (:issue:`42452`)
273274

274275
Reshaping
275276
^^^^^^^^^

pandas/compat/pyarrow.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
pa_version_under2p0 = _palv < Version("2.0.0")
1212
pa_version_under3p0 = _palv < Version("3.0.0")
1313
pa_version_under4p0 = _palv < Version("4.0.0")
14+
pa_version_under5p0 = _palv < Version("5.0.0")
1415
except ImportError:
1516
pa_version_under1p0 = True
1617
pa_version_under2p0 = True
1718
pa_version_under3p0 = True
1819
pa_version_under4p0 = True
20+
pa_version_under5p0 = True

pandas/core/dtypes/base.py

+38-9
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
TYPE_CHECKING,
99
Any,
1010
TypeVar,
11+
cast,
12+
overload,
1113
)
1214

1315
import numpy as np
1416

1517
from pandas._libs.hashtable import object_hash
1618
from pandas._typing import (
1719
DtypeObj,
20+
npt,
1821
type_t,
1922
)
2023
from pandas.errors import AbstractMethodError
@@ -29,7 +32,7 @@
2932
from pandas.core.arrays import ExtensionArray
3033

3134
# To parameterize on same ExtensionDtype
32-
E = TypeVar("E", bound="ExtensionDtype")
35+
ExtensionDtypeT = TypeVar("ExtensionDtypeT", bound="ExtensionDtype")
3336

3437

3538
class ExtensionDtype:
@@ -206,7 +209,9 @@ def construct_array_type(cls) -> type_t[ExtensionArray]:
206209
raise AbstractMethodError(cls)
207210

208211
@classmethod
209-
def construct_from_string(cls, string: str):
212+
def construct_from_string(
213+
cls: type_t[ExtensionDtypeT], string: str
214+
) -> ExtensionDtypeT:
210215
r"""
211216
Construct this type from a string.
212217
@@ -368,7 +373,7 @@ def _can_hold_na(self) -> bool:
368373
return True
369374

370375

371-
def register_extension_dtype(cls: type[E]) -> type[E]:
376+
def register_extension_dtype(cls: type_t[ExtensionDtypeT]) -> type_t[ExtensionDtypeT]:
372377
"""
373378
Register an ExtensionType with pandas as class decorator.
374379
@@ -409,9 +414,9 @@ class Registry:
409414
"""
410415

411416
def __init__(self):
412-
self.dtypes: list[type[ExtensionDtype]] = []
417+
self.dtypes: list[type_t[ExtensionDtype]] = []
413418

414-
def register(self, dtype: type[ExtensionDtype]) -> None:
419+
def register(self, dtype: type_t[ExtensionDtype]) -> None:
415420
"""
416421
Parameters
417422
----------
@@ -422,22 +427,46 @@ def register(self, dtype: type[ExtensionDtype]) -> None:
422427

423428
self.dtypes.append(dtype)
424429

425-
def find(self, dtype: type[ExtensionDtype] | str) -> type[ExtensionDtype] | None:
430+
@overload
431+
def find(self, dtype: type_t[ExtensionDtypeT]) -> type_t[ExtensionDtypeT]:
432+
...
433+
434+
@overload
435+
def find(self, dtype: ExtensionDtypeT) -> ExtensionDtypeT:
436+
...
437+
438+
@overload
439+
def find(self, dtype: str) -> ExtensionDtype | None:
440+
...
441+
442+
@overload
443+
def find(
444+
self, dtype: npt.DTypeLike
445+
) -> type_t[ExtensionDtype] | ExtensionDtype | None:
446+
...
447+
448+
def find(
449+
self, dtype: type_t[ExtensionDtype] | ExtensionDtype | npt.DTypeLike
450+
) -> type_t[ExtensionDtype] | ExtensionDtype | None:
426451
"""
427452
Parameters
428453
----------
429-
dtype : Type[ExtensionDtype] or str
454+
dtype : ExtensionDtype class or instance or str or numpy dtype or python type
430455
431456
Returns
432457
-------
433458
return the first matching dtype, otherwise return None
434459
"""
435460
if not isinstance(dtype, str):
436-
dtype_type = dtype
461+
dtype_type: type_t
437462
if not isinstance(dtype, type):
438463
dtype_type = type(dtype)
464+
else:
465+
dtype_type = dtype
439466
if issubclass(dtype_type, ExtensionDtype):
440-
return dtype
467+
# cast needed here as mypy doesn't know we have figured
468+
# out it is an ExtensionDtype or type_t[ExtensionDtype]
469+
return cast("ExtensionDtype | type_t[ExtensionDtype]", dtype)
441470

442471
return None
443472

pandas/core/dtypes/common.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1765,9 +1765,7 @@ def pandas_dtype(dtype) -> DtypeObj:
17651765
# registered extension types
17661766
result = registry.find(dtype)
17671767
if result is not None:
1768-
# error: Incompatible return value type (got "Type[ExtensionDtype]",
1769-
# expected "Union[dtype, ExtensionDtype]")
1770-
return result # type: ignore[return-value]
1768+
return result
17711769

17721770
# try a numpy dtype
17731771
# raise a consistent TypeError if failed

pandas/core/frame.py

+5
Original file line numberDiff line numberDiff line change
@@ -4280,6 +4280,11 @@ def check_int_infer_dtype(dtypes):
42804280
# error: Argument 1 to "append" of "list" has incompatible type
42814281
# "Type[signedinteger[Any]]"; expected "Type[signedinteger[Any]]"
42824282
converted_dtypes.append(np.int64) # type: ignore[arg-type]
4283+
elif dtype == "float" or dtype is float:
4284+
# GH#42452 : np.dtype("float") coerces to np.float64 from Numpy 1.20
4285+
converted_dtypes.extend(
4286+
[np.float64, np.float32] # type: ignore[list-item]
4287+
)
42834288
else:
42844289
# error: Argument 1 to "append" of "list" has incompatible type
42854290
# "Union[dtype[Any], ExtensionDtype]"; expected

pandas/io/formats/style.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -2347,15 +2347,15 @@ def highlight_max(
23472347
Styler.highlight_quantile: Highlight values defined by a quantile with a style.
23482348
"""
23492349

2350-
def f(data: FrameOrSeries, props: str) -> np.ndarray:
2351-
return np.where(data == np.nanmax(data.to_numpy()), props, "")
2352-
23532350
if props is None:
23542351
props = f"background-color: {color};"
23552352
# error: Argument 1 to "apply" of "Styler" has incompatible type
23562353
# "Callable[[FrameOrSeries, str], ndarray]"; expected "Callable[..., Styler]"
23572354
return self.apply(
2358-
f, axis=axis, subset=subset, props=props # type: ignore[arg-type]
2355+
partial(_highlight_value, op="max"), # type: ignore[arg-type]
2356+
axis=axis,
2357+
subset=subset,
2358+
props=props,
23592359
)
23602360

23612361
def highlight_min(
@@ -2398,15 +2398,15 @@ def highlight_min(
23982398
Styler.highlight_quantile: Highlight values defined by a quantile with a style.
23992399
"""
24002400

2401-
def f(data: FrameOrSeries, props: str) -> np.ndarray:
2402-
return np.where(data == np.nanmin(data.to_numpy()), props, "")
2403-
24042401
if props is None:
24052402
props = f"background-color: {color};"
24062403
# error: Argument 1 to "apply" of "Styler" has incompatible type
24072404
# "Callable[[FrameOrSeries, str], ndarray]"; expected "Callable[..., Styler]"
24082405
return self.apply(
2409-
f, axis=axis, subset=subset, props=props # type: ignore[arg-type]
2406+
partial(_highlight_value, op="min"), # type: ignore[arg-type]
2407+
axis=axis,
2408+
subset=subset,
2409+
props=props,
24102410
)
24112411

24122412
def highlight_between(
@@ -2912,6 +2912,16 @@ def _highlight_between(
29122912
return np.where(g_left & l_right, props, "")
29132913

29142914

2915+
def _highlight_value(data: FrameOrSeries, op: str, props: str) -> np.ndarray:
2916+
"""
2917+
Return an array of css strings based on the condition of values matching an op.
2918+
"""
2919+
value = getattr(data, op)(skipna=True)
2920+
if isinstance(data, DataFrame): # min/max must be done twice to return scalar
2921+
value = getattr(value, op)(skipna=True)
2922+
return np.where(data == value, props, "")
2923+
2924+
29152925
def _bar(
29162926
data: FrameOrSeries,
29172927
align: str | float | int | Callable,

pandas/io/formats/style_render.py

+1
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ def _translate_header(
353353
self.data.index.names
354354
and com.any_not_none(*self.data.index.names)
355355
and not self.hide_index_
356+
and not self.hide_columns_
356357
):
357358
index_names = [
358359
_element(

pandas/tests/frame/methods/test_select_dtypes.py

+34
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,37 @@ def test_select_dtypes_numeric_nullable_string(self, nullable_string_dtype):
407407
df = DataFrame(arr)
408408
is_selected = df.select_dtypes(np.number).shape == df.shape
409409
assert not is_selected
410+
411+
@pytest.mark.parametrize(
412+
"expected, float_dtypes",
413+
[
414+
[
415+
DataFrame(
416+
{"A": range(3), "B": range(5, 8), "C": range(10, 7, -1)}
417+
).astype(dtype={"A": float, "B": np.float64, "C": np.float32}),
418+
float,
419+
],
420+
[
421+
DataFrame(
422+
{"A": range(3), "B": range(5, 8), "C": range(10, 7, -1)}
423+
).astype(dtype={"A": float, "B": np.float64, "C": np.float32}),
424+
"float",
425+
],
426+
[DataFrame({"C": range(10, 7, -1)}, dtype=np.float32), np.float32],
427+
[
428+
DataFrame({"A": range(3), "B": range(5, 8)}).astype(
429+
dtype={"A": float, "B": np.float64}
430+
),
431+
np.float64,
432+
],
433+
],
434+
)
435+
def test_select_dtypes_float_dtype(self, expected, float_dtypes):
436+
# GH#42452
437+
dtype_dict = {"A": float, "B": np.float64, "C": np.float32}
438+
df = DataFrame(
439+
{"A": range(3), "B": range(5, 8), "C": range(10, 7, -1)},
440+
)
441+
df = df.astype(dtype_dict)
442+
result = df.select_dtypes(include=float_dtypes)
443+
tm.assert_frame_equal(result, expected)

pandas/tests/io/formats/style/test_highlight.py

+22-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import pytest
33

44
from pandas import (
5+
NA,
56
DataFrame,
67
IndexSlice,
78
)
8-
import pandas._testing as tm
99

1010
pytest.importorskip("jinja2")
1111

@@ -55,9 +55,7 @@ def test_highlight_minmax_basic(df, f):
5555
}
5656
if f == "highlight_min":
5757
df = -df
58-
with tm.assert_produces_warning(RuntimeWarning):
59-
# All-NaN slice encountered
60-
result = getattr(df.style, f)(axis=1, color="red")._compute().ctx
58+
result = getattr(df.style, f)(axis=1, color="red")._compute().ctx
6159
assert result == expected
6260

6361

@@ -78,6 +76,26 @@ def test_highlight_minmax_ext(df, f, kwargs):
7876
assert result == expected
7977

8078

79+
@pytest.mark.parametrize("f", ["highlight_min", "highlight_max"])
80+
@pytest.mark.parametrize("axis", [None, 0, 1])
81+
def test_highlight_minmax_nulls(f, axis):
82+
# GH 42750
83+
expected = {
84+
(1, 0): [("background-color", "yellow")],
85+
(1, 1): [("background-color", "yellow")],
86+
}
87+
if axis == 1:
88+
expected.update({(2, 1): [("background-color", "yellow")]})
89+
90+
if f == "highlight_max":
91+
df = DataFrame({"a": [NA, 1, None], "b": [np.nan, 1, -1]})
92+
else:
93+
df = DataFrame({"a": [NA, -1, None], "b": [np.nan, -1, 1]})
94+
95+
result = getattr(df.style, f)(axis=axis)._compute().ctx
96+
assert result == expected
97+
98+
8199
@pytest.mark.parametrize(
82100
"kwargs",
83101
[

pandas/tests/io/formats/style/test_style.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ def test_hide_column_headers(self):
11311131

11321132
self.df.index.name = "some_name"
11331133
ctx = self.df.style.hide_columns()._translate(True, True)
1134-
assert len(ctx["head"]) == 1 # only a single row for index names: no col heads
1134+
assert len(ctx["head"]) == 0 # no header for index names, changed in #42101
11351135

11361136
def test_hide_single_index(self):
11371137
# GH 14194

0 commit comments

Comments
 (0)