|
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