From 7ccd484c064cf389e4f19550eab408782ef11224 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 3 Oct 2019 10:50:41 -0700 Subject: [PATCH] TST: port maybe_promote tests from #23982 (#28764) --- pandas/tests/dtypes/cast/test_promote.py | 153 +++++++++++++++++++++-- 1 file changed, 144 insertions(+), 9 deletions(-) diff --git a/pandas/tests/dtypes/cast/test_promote.py b/pandas/tests/dtypes/cast/test_promote.py index 1b7de9b20f42f0..7acff3477ce0fe 100644 --- a/pandas/tests/dtypes/cast/test_promote.py +++ b/pandas/tests/dtypes/cast/test_promote.py @@ -227,9 +227,72 @@ def test_maybe_promote_float_with_int(float_dtype, any_int_dtype, box): ) -def test_maybe_promote_float_with_float(): - # placeholder due to too many xfails; see GH 23982 / 25425 - pass +@pytest.mark.parametrize( + "dtype, fill_value, expected_dtype", + [ + # float filled with float + ("float32", 1, "float32"), + ("float32", np.finfo("float32").max * 1.1, "float64"), + ("float64", 1, "float64"), + ("float64", np.finfo("float32").max * 1.1, "float64"), + # complex filled with float + ("complex64", 1, "complex64"), + ("complex64", np.finfo("float32").max * 1.1, "complex128"), + ("complex128", 1, "complex128"), + ("complex128", np.finfo("float32").max * 1.1, "complex128"), + # float filled with complex + ("float32", 1 + 1j, "complex64"), + ("float32", np.finfo("float32").max * (1.1 + 1j), "complex128"), + ("float64", 1 + 1j, "complex128"), + ("float64", np.finfo("float32").max * (1.1 + 1j), "complex128"), + # complex filled with complex + ("complex64", 1 + 1j, "complex64"), + ("complex64", np.finfo("float32").max * (1.1 + 1j), "complex128"), + ("complex128", 1 + 1j, "complex128"), + ("complex128", np.finfo("float32").max * (1.1 + 1j), "complex128"), + ], +) +def test_maybe_promote_float_with_float(dtype, fill_value, expected_dtype, box): + + dtype = np.dtype(dtype) + expected_dtype = np.dtype(expected_dtype) + boxed, box_dtype = box # read from parametrized fixture + + if box_dtype == object: + pytest.xfail("falsely upcasts to object") + if boxed and is_float_dtype(dtype) and is_complex_dtype(expected_dtype): + pytest.xfail("does not upcast to complex") + if (dtype, expected_dtype) in [ + ("float32", "float64"), + ("float32", "complex64"), + ("complex64", "complex128"), + ]: + pytest.xfail("does not upcast correctly depending on value") + # this following xfails are "only" a consequence of the - now strictly + # enforced - principle that maybe_promote_with_scalar always casts + if not boxed and abs(fill_value) < 2: + pytest.xfail("wrong return type of fill_value") + if ( + not boxed + and dtype == "complex128" + and expected_dtype == "complex128" + and is_float_dtype(type(fill_value)) + ): + pytest.xfail("wrong return type of fill_value") + + # output is not a generic float, but corresponds to expected_dtype + exp_val_for_scalar = np.array([fill_value], dtype=expected_dtype)[0] + exp_val_for_array = np.nan + + _check_promote( + dtype, + fill_value, + boxed, + box_dtype, + expected_dtype, + exp_val_for_scalar, + exp_val_for_array, + ) def test_maybe_promote_bool_with_any(any_numpy_dtype_reduced, box): @@ -300,9 +363,45 @@ def test_maybe_promote_any_with_bytes(): pass -def test_maybe_promote_datetime64_with_any(): - # placeholder due to too many xfails; see GH 23982 / 25425 - pass +def test_maybe_promote_datetime64_with_any( + datetime64_dtype, any_numpy_dtype_reduced, box +): + dtype = np.dtype(datetime64_dtype) + fill_dtype = np.dtype(any_numpy_dtype_reduced) + boxed, box_dtype = box # read from parametrized fixture + + if is_datetime64_dtype(fill_dtype): + if box_dtype == object: + pytest.xfail("falsely upcasts to object") + else: + if boxed and box_dtype is None: + pytest.xfail("does not upcast to object") + if not boxed: + pytest.xfail("does not upcast to object or raises") + + # create array of given dtype; casts "1" to correct dtype + fill_value = np.array([1], dtype=fill_dtype)[0] + + # filling datetime with anything but datetime casts to object + if is_datetime64_dtype(fill_dtype): + expected_dtype = dtype + # for datetime dtypes, scalar values get cast to to_datetime64 + exp_val_for_scalar = pd.Timestamp(fill_value).to_datetime64() + exp_val_for_array = np.datetime64("NaT", "ns") + else: + expected_dtype = np.dtype(object) + exp_val_for_scalar = fill_value + exp_val_for_array = np.nan + + _check_promote( + dtype, + fill_value, + boxed, + box_dtype, + expected_dtype, + exp_val_for_scalar, + exp_val_for_array, + ) # override parametrization of box to add special case for dt_dtype @@ -505,9 +604,45 @@ def test_maybe_promote_any_numpy_dtype_with_datetimetz( ) -def test_maybe_promote_timedelta64_with_any(): - # placeholder due to too many xfails; see GH 23982 / 25425 - pass +def test_maybe_promote_timedelta64_with_any( + timedelta64_dtype, any_numpy_dtype_reduced, box +): + dtype = np.dtype(timedelta64_dtype) + fill_dtype = np.dtype(any_numpy_dtype_reduced) + boxed, box_dtype = box # read from parametrized fixture + + if is_timedelta64_dtype(fill_dtype): + if box_dtype == object: + pytest.xfail("falsely upcasts to object") + else: + if boxed and box_dtype is None: + pytest.xfail("does not upcast to object") + if not boxed: + pytest.xfail("does not upcast to object or raises") + + # create array of given dtype; casts "1" to correct dtype + fill_value = np.array([1], dtype=fill_dtype)[0] + + # filling timedelta with anything but timedelta casts to object + if is_timedelta64_dtype(fill_dtype): + expected_dtype = dtype + # for timedelta dtypes, scalar values get cast to pd.Timedelta.value + exp_val_for_scalar = pd.Timedelta(fill_value).to_timedelta64() + exp_val_for_array = np.timedelta64("NaT", "ns") + else: + expected_dtype = np.dtype(object) + exp_val_for_scalar = fill_value + exp_val_for_array = np.nan + + _check_promote( + dtype, + fill_value, + boxed, + box_dtype, + expected_dtype, + exp_val_for_scalar, + exp_val_for_array, + ) @pytest.mark.parametrize(