|
23 | 23 | is_timedelta64_dtype, |
24 | 24 | ) |
25 | 25 | from pandas.core.dtypes.dtypes import DatetimeTZDtype, PandasExtensionDtype |
| 26 | +from pandas.core.dtypes.missing import isna |
26 | 27 |
|
27 | 28 | import pandas as pd |
28 | 29 |
|
@@ -95,6 +96,7 @@ def _safe_dtype_assert(left_dtype, right_dtype): |
95 | 96 | """ |
96 | 97 | Compare two dtypes without raising TypeError. |
97 | 98 | """ |
| 99 | + __tracebackhide__ = True |
98 | 100 | if isinstance(right_dtype, PandasExtensionDtype): |
99 | 101 | # switch order of equality check because numpy dtypes (e.g. if |
100 | 102 | # left_dtype is np.object_) do not know some expected dtypes (e.g. |
@@ -157,20 +159,17 @@ def _check_promote( |
157 | 159 |
|
158 | 160 | _safe_dtype_assert(result_dtype, expected_dtype) |
159 | 161 |
|
160 | | - # for equal values, also check type (relevant e.g. for int vs float, resp. |
161 | | - # for different datetimes and timedeltas) |
162 | | - match_value = ( |
163 | | - result_fill_value |
164 | | - == expected_fill_value |
165 | | - # disabled type check due to too many xfails; GH 23982/25425 |
166 | | - # and type(result_fill_value) == type(expected_fill_value) |
167 | | - ) |
| 162 | + # GH#23982/25425 require the same type in addition to equality/NA-ness |
| 163 | + res_type = type(result_fill_value) |
| 164 | + ex_type = type(expected_fill_value) |
| 165 | + assert res_type == ex_type |
| 166 | + |
| 167 | + match_value = result_fill_value == expected_fill_value |
168 | 168 |
|
| 169 | + # Note: type check above ensures that we have the _same_ NA value |
169 | 170 | # for missing values, None == None and iNaT == iNaT (which is checked |
170 | 171 | # through match_value above), but np.nan != np.nan and pd.NaT != pd.NaT |
171 | | - match_missing = (result_fill_value is np.nan and expected_fill_value is np.nan) or ( |
172 | | - result_fill_value is NaT and expected_fill_value is NaT |
173 | | - ) |
| 172 | + match_missing = isna(result_fill_value) and isna(expected_fill_value) |
174 | 173 |
|
175 | 174 | assert match_value or match_missing |
176 | 175 |
|
@@ -251,7 +250,9 @@ def test_maybe_promote_bool_with_any(any_numpy_dtype_reduced, box): |
251 | 250 |
|
252 | 251 | if boxed and fill_dtype == bool: |
253 | 252 | pytest.xfail("falsely upcasts to object") |
254 | | - if boxed and box_dtype is None and is_datetime_or_timedelta_dtype(fill_dtype): |
| 253 | + if boxed and box_dtype is None and fill_dtype.kind == "M": |
| 254 | + pytest.xfail("wrongly casts fill_value") |
| 255 | + if boxed and box_dtype is None and fill_dtype.kind == "m": |
255 | 256 | pytest.xfail("wrongly casts fill_value") |
256 | 257 |
|
257 | 258 | # create array of given dtype; casts "1" to correct dtype |
@@ -282,7 +283,9 @@ def test_maybe_promote_any_with_bool(any_numpy_dtype_reduced, box): |
282 | 283 | pytest.xfail("falsely upcasts to object") |
283 | 284 | if boxed and dtype not in (str, object) and box_dtype is None: |
284 | 285 | pytest.xfail("falsely upcasts to object") |
285 | | - if not boxed and is_datetime_or_timedelta_dtype(dtype): |
| 286 | + if not boxed and dtype.kind == "M": |
| 287 | + pytest.xfail("raises error") |
| 288 | + if not boxed and dtype.kind == "m": |
286 | 289 | pytest.xfail("raises error") |
287 | 290 |
|
288 | 291 | # filling anything but bool with bool casts to object |
@@ -393,9 +396,6 @@ def test_maybe_promote_datetimetz_with_any_numpy_dtype( |
393 | 396 | fill_dtype = np.dtype(any_numpy_dtype_reduced) |
394 | 397 | boxed, box_dtype = box # read from parametrized fixture |
395 | 398 |
|
396 | | - if box_dtype != object: |
397 | | - pytest.xfail("does not upcast correctly") |
398 | | - |
399 | 399 | # create array of given dtype; casts "1" to correct dtype |
400 | 400 | fill_value = np.array([1], dtype=fill_dtype)[0] |
401 | 401 |
|
@@ -430,8 +430,6 @@ def test_maybe_promote_datetimetz_with_datetimetz( |
430 | 430 | pytest.xfail("Cannot process fill_value with this dtype, see GH 24310") |
431 | 431 | if dtype.tz == fill_dtype.tz and boxed: |
432 | 432 | pytest.xfail("falsely upcasts") |
433 | | - if dtype.tz != fill_dtype.tz and not boxed: |
434 | | - pytest.xfail("falsely upcasts") |
435 | 433 |
|
436 | 434 | # create array of given dtype; casts "1" to correct dtype |
437 | 435 | fill_value = pd.Series([10 ** 9], dtype=fill_dtype)[0] |
@@ -466,14 +464,10 @@ def test_maybe_promote_datetimetz_with_na(tz_aware_fixture, fill_value, box): |
466 | 464 | dtype = DatetimeTZDtype(tz=tz_aware_fixture) |
467 | 465 | boxed, box_dtype = box # read from parametrized fixture |
468 | 466 |
|
469 | | - if boxed and ( |
470 | | - box_dtype == object |
471 | | - or (box_dtype is None and (fill_value is None or fill_value is NaT)) |
472 | | - ): |
473 | | - pytest.xfail("false upcasts to object") |
474 | 467 | # takes the opinion that DatetimeTZ should have single na-marker |
475 | 468 | # using iNaT would lead to errors elsewhere -> NaT |
476 | 469 | if not boxed and fill_value == iNaT: |
| 470 | + # TODO: are we sure iNaT _should_ be cast to NaT? |
477 | 471 | pytest.xfail("wrong missing value marker") |
478 | 472 |
|
479 | 473 | expected_dtype = dtype |
@@ -509,8 +503,10 @@ def test_maybe_promote_any_numpy_dtype_with_datetimetz( |
509 | 503 | fill_dtype = DatetimeTZDtype(tz=tz_aware_fixture) |
510 | 504 | boxed, box_dtype = box # read from parametrized fixture |
511 | 505 |
|
512 | | - if is_datetime_or_timedelta_dtype(dtype) and not boxed: |
| 506 | + if dtype.kind == "m" and not boxed: |
513 | 507 | pytest.xfail("raises error") |
| 508 | + elif dtype.kind == "M" and not boxed: |
| 509 | + pytest.xfail("Comes back as M8 instead of object") |
514 | 510 |
|
515 | 511 | fill_value = pd.Series([fill_value], dtype=fill_dtype)[0] |
516 | 512 |
|
@@ -566,19 +562,6 @@ def test_maybe_promote_any_with_timedelta64( |
566 | 562 | else: |
567 | 563 | if boxed and box_dtype is None and is_timedelta64_dtype(type(fill_value)): |
568 | 564 | pytest.xfail("does not upcast correctly") |
569 | | - if ( |
570 | | - not boxed |
571 | | - and is_timedelta64_dtype(type(fill_value)) |
572 | | - and ( |
573 | | - is_integer_dtype(dtype) |
574 | | - or is_float_dtype(dtype) |
575 | | - or is_complex_dtype(dtype) |
576 | | - or issubclass(dtype.type, np.bytes_) |
577 | | - ) |
578 | | - ): |
579 | | - pytest.xfail("does not upcast correctly") |
580 | | - if box_dtype == "td_dtype": |
581 | | - pytest.xfail("falsely upcasts") |
582 | 565 | if not boxed and is_datetime64_dtype(dtype): |
583 | 566 | pytest.xfail("raises error") |
584 | 567 |
|
@@ -612,7 +595,9 @@ def test_maybe_promote_string_with_any(string_dtype, any_numpy_dtype_reduced, bo |
612 | 595 | fill_dtype = np.dtype(any_numpy_dtype_reduced) |
613 | 596 | boxed, box_dtype = box # read from parametrized fixture |
614 | 597 |
|
615 | | - if boxed and box_dtype is None and is_datetime_or_timedelta_dtype(fill_dtype): |
| 598 | + if boxed and box_dtype is None and fill_dtype.kind == "m": |
| 599 | + pytest.xfail("wrong missing value marker") |
| 600 | + if boxed and box_dtype is None and fill_dtype.kind == "M": |
616 | 601 | pytest.xfail("wrong missing value marker") |
617 | 602 |
|
618 | 603 | # create array of given dtype; casts "1" to correct dtype |
@@ -652,17 +637,6 @@ def test_maybe_promote_any_with_string(any_numpy_dtype_reduced, string_dtype, bo |
652 | 637 |
|
653 | 638 | if is_datetime_or_timedelta_dtype(dtype) and box_dtype != object: |
654 | 639 | pytest.xfail("does not upcast or raises") |
655 | | - if ( |
656 | | - boxed |
657 | | - and box_dtype in (None, "str") |
658 | | - and ( |
659 | | - is_integer_dtype(dtype) |
660 | | - or is_float_dtype(dtype) |
661 | | - or is_complex_dtype(dtype) |
662 | | - or issubclass(dtype.type, np.bytes_) |
663 | | - ) |
664 | | - ): |
665 | | - pytest.xfail("does not upcast correctly") |
666 | 640 |
|
667 | 641 | # create array of given dtype |
668 | 642 | fill_value = "abc" |
@@ -760,19 +734,6 @@ def test_maybe_promote_any_numpy_dtype_with_na( |
760 | 734 | pytest.xfail("does not upcast to object") |
761 | 735 | elif dtype == "uint64" and not boxed and fill_value == iNaT: |
762 | 736 | pytest.xfail("does not upcast correctly") |
763 | | - elif is_datetime_or_timedelta_dtype(dtype) and boxed: |
764 | | - pytest.xfail("falsely upcasts to object") |
765 | | - elif ( |
766 | | - boxed |
767 | | - and ( |
768 | | - is_integer_dtype(dtype) or is_float_dtype(dtype) or is_complex_dtype(dtype) |
769 | | - ) |
770 | | - and fill_value is not NaT |
771 | | - and dtype != "uint64" |
772 | | - ): |
773 | | - pytest.xfail("falsely upcasts to object") |
774 | | - elif boxed and dtype == "uint64" and (fill_value is np.nan or fill_value is None): |
775 | | - pytest.xfail("falsely upcasts to object") |
776 | 737 | # below: opinionated that iNaT should be interpreted as missing value |
777 | 738 | elif ( |
778 | 739 | not boxed |
|
0 commit comments