|
36 | 36 | assert_equal,
|
37 | 37 | assert_identical,
|
38 | 38 | assert_no_warnings,
|
| 39 | + has_pandas_version_two, |
39 | 40 | raise_if_dask_computes,
|
40 | 41 | requires_cupy,
|
41 | 42 | requires_dask,
|
| 43 | + requires_pandas_version_two, |
42 | 44 | requires_pint,
|
43 | 45 | requires_sparse,
|
44 | 46 | source_ndarray,
|
@@ -2520,6 +2522,26 @@ def test_datetime(self):
|
2520 | 2522 | assert np.ndarray == type(actual)
|
2521 | 2523 | assert np.dtype("datetime64[ns]") == actual.dtype
|
2522 | 2524 |
|
| 2525 | + @requires_pandas_version_two |
| 2526 | + def test_tz_datetime(self) -> None: |
| 2527 | + tz = pytz.timezone("US/Eastern") |
| 2528 | + times_ns = pd.date_range("2000", periods=1, tz=tz) |
| 2529 | + |
| 2530 | + times_s = times_ns.astype(pd.DatetimeTZDtype("s", tz)) |
| 2531 | + with warnings.catch_warnings(): |
| 2532 | + warnings.simplefilter("ignore") |
| 2533 | + actual = as_compatible_data(times_s) |
| 2534 | + assert actual.array == times_s |
| 2535 | + assert actual.array.dtype == pd.DatetimeTZDtype("ns", tz) |
| 2536 | + |
| 2537 | + series = pd.Series(times_s) |
| 2538 | + with warnings.catch_warnings(): |
| 2539 | + warnings.simplefilter("ignore") |
| 2540 | + actual = as_compatible_data(series) |
| 2541 | + |
| 2542 | + np.testing.assert_array_equal(actual, series.values) |
| 2543 | + assert actual.dtype == np.dtype("datetime64[ns]") |
| 2544 | + |
2523 | 2545 | def test_full_like(self) -> None:
|
2524 | 2546 | # For more thorough tests, see test_variable.py
|
2525 | 2547 | orig = Variable(
|
@@ -2790,3 +2812,110 @@ def test_from_pint_wrapping_dask(self, Var):
|
2790 | 2812 | result = v.as_numpy()
|
2791 | 2813 | assert_identical(result, Var("x", arr))
|
2792 | 2814 | np.testing.assert_equal(v.to_numpy(), arr)
|
| 2815 | + |
| 2816 | + |
| 2817 | +@pytest.mark.parametrize( |
| 2818 | + ("values", "warns_under_pandas_version_two"), |
| 2819 | + [ |
| 2820 | + (np.datetime64("2000-01-01", "ns"), False), |
| 2821 | + (np.datetime64("2000-01-01", "s"), True), |
| 2822 | + (np.array([np.datetime64("2000-01-01", "ns")]), False), |
| 2823 | + (np.array([np.datetime64("2000-01-01", "s")]), True), |
| 2824 | + (pd.date_range("2000", periods=1), False), |
| 2825 | + (datetime(2000, 1, 1), False), |
| 2826 | + (np.array([datetime(2000, 1, 1)]), False), |
| 2827 | + (pd.date_range("2000", periods=1, tz=pytz.timezone("US/Eastern")), False), |
| 2828 | + ( |
| 2829 | + pd.Series(pd.date_range("2000", periods=1, tz=pytz.timezone("US/Eastern"))), |
| 2830 | + False, |
| 2831 | + ), |
| 2832 | + ], |
| 2833 | + ids=lambda x: f"{x}", |
| 2834 | +) |
| 2835 | +def test_datetime_conversion_warning(values, warns_under_pandas_version_two) -> None: |
| 2836 | + dims = ["time"] if isinstance(values, (np.ndarray, pd.Index, pd.Series)) else [] |
| 2837 | + if warns_under_pandas_version_two and has_pandas_version_two: |
| 2838 | + with pytest.warns(UserWarning, match="non-nanosecond precision datetime"): |
| 2839 | + var = Variable(dims, values) |
| 2840 | + else: |
| 2841 | + with warnings.catch_warnings(): |
| 2842 | + warnings.simplefilter("error") |
| 2843 | + var = Variable(dims, values) |
| 2844 | + |
| 2845 | + if var.dtype.kind == "M": |
| 2846 | + assert var.dtype == np.dtype("datetime64[ns]") |
| 2847 | + else: |
| 2848 | + # The only case where a non-datetime64 dtype can occur currently is in |
| 2849 | + # the case that the variable is backed by a timezone-aware |
| 2850 | + # DatetimeIndex, and thus is hidden within the PandasIndexingAdapter class. |
| 2851 | + assert var._data.array.dtype == pd.DatetimeTZDtype( |
| 2852 | + "ns", pytz.timezone("US/Eastern") |
| 2853 | + ) |
| 2854 | + |
| 2855 | + |
| 2856 | +@requires_pandas_version_two |
| 2857 | +def test_pandas_two_only_datetime_conversion_warnings() -> None: |
| 2858 | + # Note these tests rely on pandas features that are only present in pandas |
| 2859 | + # 2.0.0 and above, and so for now cannot be parametrized. |
| 2860 | + cases = [ |
| 2861 | + (pd.date_range("2000", periods=1), "datetime64[s]"), |
| 2862 | + (pd.Series(pd.date_range("2000", periods=1)), "datetime64[s]"), |
| 2863 | + ( |
| 2864 | + pd.date_range("2000", periods=1, tz=pytz.timezone("US/Eastern")), |
| 2865 | + pd.DatetimeTZDtype("s", pytz.timezone("US/Eastern")), |
| 2866 | + ), |
| 2867 | + ( |
| 2868 | + pd.Series(pd.date_range("2000", periods=1, tz=pytz.timezone("US/Eastern"))), |
| 2869 | + pd.DatetimeTZDtype("s", pytz.timezone("US/Eastern")), |
| 2870 | + ), |
| 2871 | + ] |
| 2872 | + for data, dtype in cases: |
| 2873 | + with pytest.warns(UserWarning, match="non-nanosecond precision datetime"): |
| 2874 | + var = Variable(["time"], data.astype(dtype)) |
| 2875 | + |
| 2876 | + if var.dtype.kind == "M": |
| 2877 | + assert var.dtype == np.dtype("datetime64[ns]") |
| 2878 | + else: |
| 2879 | + # The only case where a non-datetime64 dtype can occur currently is in |
| 2880 | + # the case that the variable is backed by a timezone-aware |
| 2881 | + # DatetimeIndex, and thus is hidden within the PandasIndexingAdapter class. |
| 2882 | + assert var._data.array.dtype == pd.DatetimeTZDtype( |
| 2883 | + "ns", pytz.timezone("US/Eastern") |
| 2884 | + ) |
| 2885 | + |
| 2886 | + |
| 2887 | +@pytest.mark.parametrize( |
| 2888 | + ("values", "warns_under_pandas_version_two"), |
| 2889 | + [ |
| 2890 | + (np.timedelta64(10, "ns"), False), |
| 2891 | + (np.timedelta64(10, "s"), True), |
| 2892 | + (np.array([np.timedelta64(10, "ns")]), False), |
| 2893 | + (np.array([np.timedelta64(10, "s")]), True), |
| 2894 | + (pd.timedelta_range("1", periods=1), False), |
| 2895 | + (timedelta(days=1), False), |
| 2896 | + (np.array([timedelta(days=1)]), False), |
| 2897 | + ], |
| 2898 | + ids=lambda x: f"{x}", |
| 2899 | +) |
| 2900 | +def test_timedelta_conversion_warning(values, warns_under_pandas_version_two) -> None: |
| 2901 | + dims = ["time"] if isinstance(values, (np.ndarray, pd.Index)) else [] |
| 2902 | + if warns_under_pandas_version_two and has_pandas_version_two: |
| 2903 | + with pytest.warns(UserWarning, match="non-nanosecond precision timedelta"): |
| 2904 | + var = Variable(dims, values) |
| 2905 | + else: |
| 2906 | + with warnings.catch_warnings(): |
| 2907 | + warnings.simplefilter("error") |
| 2908 | + var = Variable(dims, values) |
| 2909 | + |
| 2910 | + assert var.dtype == np.dtype("timedelta64[ns]") |
| 2911 | + |
| 2912 | + |
| 2913 | +@requires_pandas_version_two |
| 2914 | +def test_pandas_two_only_timedelta_conversion_warning() -> None: |
| 2915 | + # Note this test relies on a pandas feature that is only present in pandas |
| 2916 | + # 2.0.0 and above, and so for now cannot be parametrized. |
| 2917 | + data = pd.timedelta_range("1", periods=1).astype("timedelta64[s]") |
| 2918 | + with pytest.warns(UserWarning, match="non-nanosecond precision timedelta"): |
| 2919 | + var = Variable(["time"], data) |
| 2920 | + |
| 2921 | + assert var.dtype == np.dtype("timedelta64[ns]") |
0 commit comments