From 6868618c885255205fcfb3d064bf2a6f09f5fb14 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Thu, 6 Apr 2023 08:10:24 -0400 Subject: [PATCH 01/10] [test-upstream] use nanosecond-precision timestamps for now --- doc/user-guide/weather-climate.rst | 16 +++++++++++----- xarray/coding/cftime_offsets.py | 13 ++++++++++--- xarray/coding/cftimeindex.py | 2 +- xarray/coding/times.py | 20 ++++++++++++++++---- xarray/core/pdcompat.py | 13 +++++++++++++ 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/doc/user-guide/weather-climate.rst b/doc/user-guide/weather-climate.rst index 30876eb36bc..e08784b3e09 100644 --- a/doc/user-guide/weather-climate.rst +++ b/doc/user-guide/weather-climate.rst @@ -57,14 +57,14 @@ CF-compliant coordinate variables .. _CFTimeIndex: -Non-standard calendars and dates outside the Timestamp-valid range ------------------------------------------------------------------- +Non-standard calendars and dates outside the nanosecond-precision range +----------------------------------------------------------------------- Through the standalone ``cftime`` library and a custom subclass of :py:class:`pandas.Index`, xarray supports a subset of the indexing functionality enabled through the standard :py:class:`pandas.DatetimeIndex` for dates from non-standard calendars commonly used in climate science or dates -using a standard calendar, but outside the `Timestamp-valid range`_ +using a standard calendar, but outside the `nanosecond-precision range`_ (approximately between years 1678 and 2262). .. note:: @@ -75,13 +75,19 @@ using a standard calendar, but outside the `Timestamp-valid range`_ any of the following are true: - The dates are from a non-standard calendar - - Any dates are outside the Timestamp-valid range. + - Any dates are outside the nanosecond-precision range. Otherwise pandas-compatible dates from a standard calendar will be represented with the ``np.datetime64[ns]`` data type, enabling the use of a :py:class:`pandas.DatetimeIndex` or arrays with dtype ``np.datetime64[ns]`` and their full set of associated features. + As of pandas version 2.0.0, pandas supports non-nanosecond precision datetime + values. For the time being, xarray still automatically casts datetime values + to nanosecond-precision for backwards compatibility with older pandas + versions; however, this is something we would like to relax going forward. + See :issue:`7493` for more discussion. + For example, you can create a DataArray indexed by a time coordinate with dates from a no-leap calendar and a :py:class:`~xarray.CFTimeIndex` will automatically be used: @@ -235,6 +241,6 @@ For data indexed by a :py:class:`~xarray.CFTimeIndex` xarray currently supports: da.resample(time="81T", closed="right", label="right", offset="3T").mean() -.. _Timestamp-valid range: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timestamp-limitations +.. _nanosecond-precision range: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timestamp-limitations .. _ISO 8601 standard: https://en.wikipedia.org/wiki/ISO_8601 .. _partial datetime string indexing: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#partial-string-indexing diff --git a/xarray/coding/cftime_offsets.py b/xarray/coding/cftime_offsets.py index 792724ecc79..a746163c3fd 100644 --- a/xarray/coding/cftime_offsets.py +++ b/xarray/coding/cftime_offsets.py @@ -57,7 +57,12 @@ format_cftime_datetime, ) from xarray.core.common import _contains_datetime_like_objects, is_np_datetime_like -from xarray.core.pdcompat import NoDefault, count_not_none, no_default +from xarray.core.pdcompat import ( + NoDefault, + count_not_none, + nanosecond_precision_timestamp, + no_default, +) from xarray.core.utils import emit_user_level_warning try: @@ -1286,8 +1291,10 @@ def date_range_like(source, calendar, use_cftime=None): if is_np_datetime_like(source.dtype): # We want to use datetime fields (datetime64 object don't have them) source_calendar = "standard" - source_start = pd.Timestamp(source_start) - source_end = pd.Timestamp(source_end) + # TODO: the strict enforcement of nanosecond precision Timestamps can be + # relaxed when addressing GitHub issue #7493. + source_start = nanosecond_precision_timestamp(source_start) + source_end = nanosecond_precision_timestamp(source_end) else: if isinstance(source, CFTimeIndex): source_calendar = source.calendar diff --git a/xarray/coding/cftimeindex.py b/xarray/coding/cftimeindex.py index 7227ba9edb6..c6a7b9f8763 100644 --- a/xarray/coding/cftimeindex.py +++ b/xarray/coding/cftimeindex.py @@ -613,7 +613,7 @@ def to_datetimeindex(self, unsafe=False): ------ ValueError If the CFTimeIndex contains dates that are not possible in the - standard calendar or outside the pandas.Timestamp-valid range. + standard calendar or outside the nanosecond-precision range. Warns ----- diff --git a/xarray/coding/times.py b/xarray/coding/times.py index f9e79863d46..e2ae7e796f1 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -23,6 +23,7 @@ from xarray.core import indexing from xarray.core.common import contains_cftime_datetimes, is_np_datetime_like from xarray.core.formatting import first_n_items, format_timestamp, last_item +from xarray.core.pdcompat import nanosecond_precision_timestamp from xarray.core.pycompat import is_duck_dask_array from xarray.core.variable import Variable @@ -224,7 +225,9 @@ def _decode_datetime_with_pandas( delta, ref_date = _unpack_netcdf_time_units(units) delta = _netcdf_to_numpy_timeunit(delta) try: - ref_date = pd.Timestamp(ref_date) + # TODO: the strict enforcement of nanosecond precision Timestamps can be + # relaxed when addressing GitHub issue #7493. + ref_date = nanosecond_precision_timestamp(ref_date) except ValueError: # ValueError is raised by pd.Timestamp for non-ISO timestamp # strings, in which case we fall back to using cftime @@ -391,7 +394,9 @@ def infer_datetime_units(dates) -> str: dates = to_datetime_unboxed(dates) dates = dates[pd.notnull(dates)] reference_date = dates[0] if len(dates) > 0 else "1970-01-01" - reference_date = pd.Timestamp(reference_date) + # TODO: the strict enforcement of nanosecond precision Timestamps can be + # relaxed when addressing GitHub issue #7493. + reference_date = nanosecond_precision_timestamp(reference_date) else: reference_date = dates[0] if len(dates) > 0 else "1970-01-01" reference_date = format_cftime_datetime(reference_date) @@ -432,6 +437,8 @@ def cftime_to_nptime(times, raise_on_invalid: bool = True) -> np.ndarray: If raise_on_invalid is True (default), invalid dates trigger a ValueError. Otherwise, the invalid element is replaced by np.NaT.""" times = np.asarray(times) + # TODO: the strict enforcement of nanosecond precision datetime values can + # be relaxed when addressing GitHub issue #7493. new = np.empty(times.shape, dtype="M8[ns]") for i, t in np.ndenumerate(times): try: @@ -439,7 +446,7 @@ def cftime_to_nptime(times, raise_on_invalid: bool = True) -> np.ndarray: # NumPy casts it safely it np.datetime64[ns] for dates outside # 1678 to 2262 (this is not currently the case for # datetime.datetime). - dt = pd.Timestamp( + dt = nanosecond_precision_timestamp( t.year, t.month, t.day, t.hour, t.minute, t.second, t.microsecond ) except ValueError as e: @@ -498,6 +505,10 @@ def convert_time_or_go_back(date, date_type): This is meant to convert end-of-month dates into a new calendar. """ + # TODO: the strict enforcement of nanosecond precision Timestamps can be + # relaxed when addressing GitHub issue #7493. + if date_type == pd.Timestamp: + date_type = nanosecond_precision_timestamp try: return date_type( date.year, @@ -641,7 +652,8 @@ def encode_cf_datetime( delta_units = _netcdf_to_numpy_timeunit(delta) time_delta = np.timedelta64(1, delta_units).astype("timedelta64[ns]") - ref_date = pd.Timestamp(_ref_date) + + ref_date = nanosecond_precision_timestamp(_ref_date) # If the ref_date Timestamp is timezone-aware, convert to UTC and # make it timezone-naive (GH 2649). diff --git a/xarray/core/pdcompat.py b/xarray/core/pdcompat.py index b20a96bb8d6..201fb52ff65 100644 --- a/xarray/core/pdcompat.py +++ b/xarray/core/pdcompat.py @@ -39,6 +39,7 @@ from typing import Literal import pandas as pd +from packaging.version import Version from xarray.coding import cftime_offsets @@ -91,3 +92,15 @@ def _convert_base_to_offset(base, freq, index): return base * freq.as_timedelta() // freq.n else: raise ValueError("Can only resample using a DatetimeIndex or CFTimeIndex.") + + +def nanosecond_precision_timestamp(*args): + """Return a nanosecond-precision Timestamp object. + + Note this function should no longer be needed after addressing GitHub issue + #7493. + """ + if Version(pd.__version__) >= Version("2.0.0"): + return pd.Timestamp(*args).as_unit("ns") + else: + return pd.Timestamp(*args) From dbe7b854183bb250fdc4105db200fc3ff0f91761 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Thu, 6 Apr 2023 09:25:50 -0400 Subject: [PATCH 02/10] [test-upstream] allow kwargs to be passed to nanosecond_precision_timestamp --- xarray/core/pdcompat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/pdcompat.py b/xarray/core/pdcompat.py index 201fb52ff65..5507c18faba 100644 --- a/xarray/core/pdcompat.py +++ b/xarray/core/pdcompat.py @@ -94,13 +94,13 @@ def _convert_base_to_offset(base, freq, index): raise ValueError("Can only resample using a DatetimeIndex or CFTimeIndex.") -def nanosecond_precision_timestamp(*args): +def nanosecond_precision_timestamp(*args, **kwargs): """Return a nanosecond-precision Timestamp object. Note this function should no longer be needed after addressing GitHub issue #7493. """ if Version(pd.__version__) >= Version("2.0.0"): - return pd.Timestamp(*args).as_unit("ns") + return pd.Timestamp(*args, **kwargs).as_unit("ns") else: - return pd.Timestamp(*args) + return pd.Timestamp(*args, **kwargs) From 058354bdac328296ac5353227a3bde9826beb530 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Wed, 12 Apr 2023 15:30:55 +0200 Subject: [PATCH 03/10] unpin `pandas` --- ci/requirements/all-but-dask.yml | 2 +- ci/requirements/doc.yml | 2 +- ci/requirements/environment-py311.yml | 2 +- ci/requirements/environment-windows-py311.yml | 2 +- ci/requirements/environment-windows.yml | 2 +- ci/requirements/environment.yml | 2 +- setup.cfg | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ci/requirements/all-but-dask.yml b/ci/requirements/all-but-dask.yml index 1387466b702..0c5c2fcdc1a 100644 --- a/ci/requirements/all-but-dask.yml +++ b/ci/requirements/all-but-dask.yml @@ -25,7 +25,7 @@ dependencies: - numbagg - numpy<1.24 - packaging - - pandas<2 + - pandas - pint - pip - pseudonetcdf diff --git a/ci/requirements/doc.yml b/ci/requirements/doc.yml index 2d35ab8724b..115d7dfa533 100644 --- a/ci/requirements/doc.yml +++ b/ci/requirements/doc.yml @@ -19,7 +19,7 @@ dependencies: - numba - numpy>=1.21,<1.24 - packaging>=21.3 - - pandas>=1.4,<2 + - pandas>=1.4 - pooch - pip - pre-commit diff --git a/ci/requirements/environment-py311.yml b/ci/requirements/environment-py311.yml index cd9edbb5052..97934e47b3b 100644 --- a/ci/requirements/environment-py311.yml +++ b/ci/requirements/environment-py311.yml @@ -27,7 +27,7 @@ dependencies: - numexpr - numpy - packaging - - pandas<2 + - pandas - pint - pip - pooch diff --git a/ci/requirements/environment-windows-py311.yml b/ci/requirements/environment-windows-py311.yml index effef0d7961..97cfb89ff6f 100644 --- a/ci/requirements/environment-windows-py311.yml +++ b/ci/requirements/environment-windows-py311.yml @@ -24,7 +24,7 @@ dependencies: # - numbagg - numpy - packaging - - pandas<2 + - pandas - pint - pip - pre-commit diff --git a/ci/requirements/environment-windows.yml b/ci/requirements/environment-windows.yml index c02907b24ac..87cce0a06a7 100644 --- a/ci/requirements/environment-windows.yml +++ b/ci/requirements/environment-windows.yml @@ -24,7 +24,7 @@ dependencies: - numbagg - numpy<1.24 - packaging - - pandas<2 + - pandas - pint - pip - pre-commit diff --git a/ci/requirements/environment.yml b/ci/requirements/environment.yml index 9abe1b295a2..626a5372801 100644 --- a/ci/requirements/environment.yml +++ b/ci/requirements/environment.yml @@ -27,7 +27,7 @@ dependencies: - numexpr - numpy<1.24 - packaging - - pandas<2 + - pandas - pint - pip - pooch diff --git a/setup.cfg b/setup.cfg index c0dd5ff9595..81b7f1c4a0e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -76,7 +76,7 @@ include_package_data = True python_requires = >=3.9 install_requires = numpy >= 1.21 # recommended to use >= 1.22 for full quantile method support - pandas >= 1.4, <2 + pandas >= 1.4 packaging >= 21.3 [options.extras_require] From 0e9d83ac4fddb8a93d051c0b757a44d19342dc73 Mon Sep 17 00:00:00 2001 From: Spencer Clark Date: Wed, 12 Apr 2023 18:18:19 -0400 Subject: [PATCH 04/10] Add type hint for nanosecond_precision_timestamp Co-authored-by: Illviljan <14371165+Illviljan@users.noreply.github.com> --- xarray/core/pdcompat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/pdcompat.py b/xarray/core/pdcompat.py index 5507c18faba..c2db154d614 100644 --- a/xarray/core/pdcompat.py +++ b/xarray/core/pdcompat.py @@ -94,7 +94,7 @@ def _convert_base_to_offset(base, freq, index): raise ValueError("Can only resample using a DatetimeIndex or CFTimeIndex.") -def nanosecond_precision_timestamp(*args, **kwargs): +def nanosecond_precision_timestamp(*args, **kwargs) -> pd.Timestamp: """Return a nanosecond-precision Timestamp object. Note this function should no longer be needed after addressing GitHub issue From 152062935bc0695564b43dd6d5008f38a6eed761 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Wed, 12 Apr 2023 18:24:01 -0400 Subject: [PATCH 05/10] Add one more TODO comment --- xarray/coding/times.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/coding/times.py b/xarray/coding/times.py index e2ae7e796f1..3745d61acc0 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -653,6 +653,8 @@ def encode_cf_datetime( delta_units = _netcdf_to_numpy_timeunit(delta) time_delta = np.timedelta64(1, delta_units).astype("timedelta64[ns]") + # TODO: the strict enforcement of nanosecond precision Timestamps can be + # relaxed when addressing GitHub issue #7493. ref_date = nanosecond_precision_timestamp(_ref_date) # If the ref_date Timestamp is timezone-aware, convert to UTC and From 7c380220acbf4f47795527df6e3572005ca19066 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Wed, 12 Apr 2023 18:26:43 -0400 Subject: [PATCH 06/10] Remove deleted attributes in CFTimeIndex documentation --- doc/api-hidden.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/api-hidden.rst b/doc/api-hidden.rst index 856014948cd..36acf273607 100644 --- a/doc/api-hidden.rst +++ b/doc/api-hidden.rst @@ -375,7 +375,6 @@ CFTimeIndex.is_floating CFTimeIndex.is_integer CFTimeIndex.is_interval - CFTimeIndex.is_mixed CFTimeIndex.is_numeric CFTimeIndex.is_object CFTimeIndex.is_type_compatible @@ -399,7 +398,6 @@ CFTimeIndex.round CFTimeIndex.searchsorted CFTimeIndex.set_names - CFTimeIndex.set_value CFTimeIndex.shift CFTimeIndex.slice_indexer CFTimeIndex.slice_locs @@ -413,7 +411,6 @@ CFTimeIndex.to_flat_index CFTimeIndex.to_frame CFTimeIndex.to_list - CFTimeIndex.to_native_types CFTimeIndex.to_numpy CFTimeIndex.to_series CFTimeIndex.tolist @@ -438,8 +435,6 @@ CFTimeIndex.hasnans CFTimeIndex.hour CFTimeIndex.inferred_type - CFTimeIndex.is_all_dates - CFTimeIndex.is_monotonic CFTimeIndex.is_monotonic_increasing CFTimeIndex.is_monotonic_decreasing CFTimeIndex.is_unique From 06029d7461fc4e36fd66b4d47f487a15107842ef Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Wed, 12 Apr 2023 18:39:20 -0400 Subject: [PATCH 07/10] Add a what's new entry --- doc/whats-new.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 48cd9735df4..0bb4f83c8bf 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -88,6 +88,12 @@ Internal Changes - Added a config.yml file with messages for the welcome bot when a Github user creates their first ever issue or pull request or has their first PR merged. (:issue:`7685`, :pull:`7685`) By `Nishtha P `_. +- Ensure that only nanosecond-precision :py:class:`pd.Timestamp` objects + continue to be used internally under pandas version 2.0.0. This is mainly to + ease the transition to this latest version of pandas. It should be relaxed + when addressing :issue:`7493`. By `Spencer Clark + `_ (:issue:`7707`, :pull:`7731`). + .. _whats-new.2023.03.0: v2023.03.0 (March 22, 2023) From 602b154eff7aeac1600b7ca048a000794d16e5b1 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Wed, 12 Apr 2023 20:14:06 -0400 Subject: [PATCH 08/10] Remove one more attribute from api-hidden.rst --- doc/api-hidden.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/api-hidden.rst b/doc/api-hidden.rst index 36acf273607..5d825be2e08 100644 --- a/doc/api-hidden.rst +++ b/doc/api-hidden.rst @@ -377,7 +377,6 @@ CFTimeIndex.is_interval CFTimeIndex.is_numeric CFTimeIndex.is_object - CFTimeIndex.is_type_compatible CFTimeIndex.isin CFTimeIndex.isna CFTimeIndex.isnull From 7ee1a97898cb5ad6e9a02d1caca162f281ea2b82 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Thu, 13 Apr 2023 06:53:03 -0400 Subject: [PATCH 09/10] Silence conversion warnings in tests --- xarray/tests/test_concat.py | 1 + xarray/tests/test_conventions.py | 1 + xarray/tests/test_dataset.py | 3 +++ xarray/tests/test_groupby.py | 2 ++ xarray/tests/test_interp.py | 1 + xarray/tests/test_plot.py | 1 + xarray/tests/test_variable.py | 10 ++++++++++ 7 files changed, 19 insertions(+) diff --git a/xarray/tests/test_concat.py b/xarray/tests/test_concat.py index f60308f8863..9021ce2522b 100644 --- a/xarray/tests/test_concat.py +++ b/xarray/tests/test_concat.py @@ -297,6 +297,7 @@ def test_concat_multiple_datasets_with_multiple_missing_variables() -> None: assert_identical(actual, expected) +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_concat_type_of_missing_fill() -> None: datasets = create_typed_datasets(2, seed=123) expected1 = concat(datasets, dim="day", fill_value=dtypes.NA) diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index 6d219f09e0e..9c40feabfb0 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -185,6 +185,7 @@ def test_emit_coordinates_attribute_in_attrs(self) -> None: assert enc["b"].attrs.get("coordinates") == "t" assert "coordinates" not in enc["b"].encoding + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_emit_coordinates_attribute_in_encoding(self) -> None: orig = Dataset( {"a": 1, "b": 1}, diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 422166234aa..6c7bfbb2b87 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -5579,6 +5579,7 @@ def test_dataset_math_auto_align(self) -> None: expected = ds + other.reindex_like(ds) assert_identical(expected, actual) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_dataset_math_errors(self) -> None: ds = self.make_example_math_dataset() @@ -6578,6 +6579,7 @@ def test_differentiate(dask, edge_order) -> None: da.differentiate("x2d") +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") @pytest.mark.parametrize("dask", [True, False]) def test_differentiate_datetime(dask) -> None: rs = np.random.RandomState(42) @@ -6774,6 +6776,7 @@ def test_cumulative_integrate(dask) -> None: da.cumulative_integrate("x2d") +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") @pytest.mark.parametrize("dask", [True, False]) @pytest.mark.parametrize("which_datetime", ["np", "cftime"]) def test_trapz_datetime(dask, which_datetime) -> None: diff --git a/xarray/tests/test_groupby.py b/xarray/tests/test_groupby.py index ccbead9dbc4..52c1af97fbf 100644 --- a/xarray/tests/test_groupby.py +++ b/xarray/tests/test_groupby.py @@ -501,6 +501,7 @@ def test_groupby_repr_datetime(obj) -> None: assert actual == expected +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") @pytest.mark.filterwarnings("ignore:invalid value encountered in divide:RuntimeWarning") def test_groupby_drops_nans() -> None: # GH2383 @@ -1805,6 +1806,7 @@ def test_upsample_interpolate(self): assert_allclose(expected, actual, rtol=1e-16) @requires_scipy + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_upsample_interpolate_bug_2197(self): dates = pd.date_range("2007-02-01", "2007-03-01", freq="D") da = xr.DataArray(np.arange(len(dates)), [("time", dates)]) diff --git a/xarray/tests/test_interp.py b/xarray/tests/test_interp.py index e66045e978d..026edf96b62 100644 --- a/xarray/tests/test_interp.py +++ b/xarray/tests/test_interp.py @@ -605,6 +605,7 @@ def test_interp_like() -> None: pytest.param("2000-01-01T12:00", 0.5, marks=pytest.mark.xfail), ], ) +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime(x_new, expected) -> None: da = xr.DataArray( np.arange(24), diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 02f7f4b9be2..b587b890ef0 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -2811,6 +2811,7 @@ def test_datetime_plot1d(self) -> None: # mpl.dates.AutoDateLocator passes and no other subclasses: assert type(ax.xaxis.get_major_locator()) is mpl.dates.AutoDateLocator + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime_plot2d(self) -> None: # Test that matplotlib-native datetime works: da = DataArray( diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index 2f571eb9a83..60e49c99fd2 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -204,6 +204,7 @@ def test_index_0d_string(self): x = self.cls(["x"], [value]) self._assertIndexedLikeNDArray(x, value, dtype) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_index_0d_datetime(self): d = datetime(2000, 1, 1) x = self.cls(["x"], [d]) @@ -275,6 +276,7 @@ def test_0d_time_data(self): expected = np.datetime64("2000-01-01", "ns") assert x[0].values == expected + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime64_conversion(self): times = pd.date_range("2000-01-01", periods=3) for values, preserve_source in [ @@ -290,6 +292,7 @@ def test_datetime64_conversion(self): same_source = source_ndarray(v.values) is source_ndarray(values) assert preserve_source == same_source + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_timedelta64_conversion(self): times = pd.timedelta_range(start=0, periods=3) for values, preserve_source in [ @@ -310,6 +313,7 @@ def test_object_conversion(self): actual = self.cls("x", data) assert actual.dtype == data.dtype + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime64_valid_range(self): data = np.datetime64("1250-01-01", "us") pderror = pd.errors.OutOfBoundsDatetime @@ -317,6 +321,7 @@ def test_datetime64_valid_range(self): self.cls(["t"], [data]) @pytest.mark.xfail(reason="pandas issue 36615") + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_timedelta64_valid_range(self): data = np.timedelta64("200000", "D") pderror = pd.errors.OutOfBoundsTimedelta @@ -1079,6 +1084,7 @@ def test_numpy_same_methods(self): v = IndexVariable("x", np.arange(5)) assert 2 == v.searchsorted(2) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime64_conversion_scalar(self): expected = np.datetime64("2000-01-01", "ns") for values in [ @@ -1091,6 +1097,7 @@ def test_datetime64_conversion_scalar(self): assert v.values == expected assert v.values.dtype == np.dtype("datetime64[ns]") + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_timedelta64_conversion_scalar(self): expected = np.timedelta64(24 * 60 * 60 * 10**9, "ns") for values in [ @@ -1117,6 +1124,7 @@ def test_0d_datetime(self): assert v.dtype == np.dtype("datetime64[ns]") assert v.values == np.datetime64("2000-01-01", "ns") + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_0d_timedelta(self): for td in [pd.to_timedelta("1s"), np.timedelta64(1, "s")]: v = Variable([], td) @@ -1555,6 +1563,7 @@ def test_transpose(self): v.transpose(..., "not_a_dim", missing_dims="warn") assert_identical(expected_ell, actual) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_transpose_0d(self): for value in [ 3.5, @@ -2540,6 +2549,7 @@ def test_masked_array(self): assert_array_equal(expected, actual) assert np.dtype(float) == actual.dtype + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime(self): expected = np.datetime64("2000-01-01") actual = as_compatible_data(expected) From 4e24ca83c650a144de356e52d532e5d2a05238a6 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Thu, 13 Apr 2023 08:15:45 -0400 Subject: [PATCH 10/10] Silence more conversion warnings --- xarray/tests/test_cftime_offsets.py | 1 + xarray/tests/test_conventions.py | 1 + xarray/tests/test_dataset.py | 105 +++++++++++++++------------- xarray/tests/test_variable.py | 1 + 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/xarray/tests/test_cftime_offsets.py b/xarray/tests/test_cftime_offsets.py index 6b628c15488..24ffab305ad 100644 --- a/xarray/tests/test_cftime_offsets.py +++ b/xarray/tests/test_cftime_offsets.py @@ -1373,6 +1373,7 @@ def test_date_range_like_same_calendar(): assert src is out +@pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_date_range_like_errors(): src = date_range("1899-02-03", periods=20, freq="D", use_cftime=False) src = src[np.arange(20) != 10] # Remove 1 day so the frequency is not inferable. diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index 9c40feabfb0..acdf9c8846e 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -168,6 +168,7 @@ def test_do_not_overwrite_user_coordinates(self) -> None: with pytest.raises(ValueError, match=r"'coordinates' found in both attrs"): conventions.encode_dataset_coordinates(orig) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_emit_coordinates_attribute_in_attrs(self) -> None: orig = Dataset( {"a": 1, "b": 1}, diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 6c7bfbb2b87..45286727f0a 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -102,57 +102,63 @@ def create_append_test_data(seed=None) -> tuple[Dataset, Dataset, Dataset]: bool_var = np.array([True, False, True], dtype=bool) bool_var_to_append = np.array([False, True], dtype=bool) - ds = xr.Dataset( - data_vars={ - "da": xr.DataArray( - rs.rand(3, 3, nt1), - coords=[lat, lon, time1], - dims=["lat", "lon", "time"], - ), - "string_var": xr.DataArray(string_var, coords=[time1], dims=["time"]), - "string_var_fixed_length": xr.DataArray( - string_var_fixed_length, coords=[time1], dims=["time"] - ), - "unicode_var": xr.DataArray( - unicode_var, coords=[time1], dims=["time"] - ).astype(np.unicode_), - "datetime_var": xr.DataArray(datetime_var, coords=[time1], dims=["time"]), - "bool_var": xr.DataArray(bool_var, coords=[time1], dims=["time"]), - } - ) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "Converting non-nanosecond") + ds = xr.Dataset( + data_vars={ + "da": xr.DataArray( + rs.rand(3, 3, nt1), + coords=[lat, lon, time1], + dims=["lat", "lon", "time"], + ), + "string_var": xr.DataArray(string_var, coords=[time1], dims=["time"]), + "string_var_fixed_length": xr.DataArray( + string_var_fixed_length, coords=[time1], dims=["time"] + ), + "unicode_var": xr.DataArray( + unicode_var, coords=[time1], dims=["time"] + ).astype(np.unicode_), + "datetime_var": xr.DataArray( + datetime_var, coords=[time1], dims=["time"] + ), + "bool_var": xr.DataArray(bool_var, coords=[time1], dims=["time"]), + } + ) - ds_to_append = xr.Dataset( - data_vars={ - "da": xr.DataArray( - rs.rand(3, 3, nt2), - coords=[lat, lon, time2], - dims=["lat", "lon", "time"], - ), - "string_var": xr.DataArray( - string_var_to_append, coords=[time2], dims=["time"] - ), - "string_var_fixed_length": xr.DataArray( - string_var_fixed_length_to_append, coords=[time2], dims=["time"] - ), - "unicode_var": xr.DataArray( - unicode_var[:nt2], coords=[time2], dims=["time"] - ).astype(np.unicode_), - "datetime_var": xr.DataArray( - datetime_var_to_append, coords=[time2], dims=["time"] - ), - "bool_var": xr.DataArray(bool_var_to_append, coords=[time2], dims=["time"]), - } - ) + ds_to_append = xr.Dataset( + data_vars={ + "da": xr.DataArray( + rs.rand(3, 3, nt2), + coords=[lat, lon, time2], + dims=["lat", "lon", "time"], + ), + "string_var": xr.DataArray( + string_var_to_append, coords=[time2], dims=["time"] + ), + "string_var_fixed_length": xr.DataArray( + string_var_fixed_length_to_append, coords=[time2], dims=["time"] + ), + "unicode_var": xr.DataArray( + unicode_var[:nt2], coords=[time2], dims=["time"] + ).astype(np.unicode_), + "datetime_var": xr.DataArray( + datetime_var_to_append, coords=[time2], dims=["time"] + ), + "bool_var": xr.DataArray( + bool_var_to_append, coords=[time2], dims=["time"] + ), + } + ) - ds_with_new_var = xr.Dataset( - data_vars={ - "new_var": xr.DataArray( - rs.rand(3, 3, nt1 + nt2), - coords=[lat, lon, time1.append(time2)], - dims=["lat", "lon", "time"], - ) - } - ) + ds_with_new_var = xr.Dataset( + data_vars={ + "new_var": xr.DataArray( + rs.rand(3, 3, nt1 + nt2), + coords=[lat, lon, time1.append(time2)], + dims=["lat", "lon", "time"], + ) + } + ) assert all(objp.data.flags.writeable for objp in ds.variables.values()) assert all(objp.data.flags.writeable for objp in ds_to_append.variables.values()) @@ -489,6 +495,7 @@ def test_constructor_1d(self) -> None: actual = Dataset({"x": [5, 6, 7, 8, 9]}) assert_identical(expected, actual) + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_constructor_0d(self) -> None: expected = Dataset({"x": ([], 1)}) for arg in [1, np.array(1), expected["x"]]: diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index 60e49c99fd2..f9fa79dd8c0 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -216,6 +216,7 @@ def test_index_0d_datetime(self): x = self.cls(["x"], pd.DatetimeIndex([d])) self._assertIndexedLikeNDArray(x, np.datetime64(d), "datetime64[ns]") + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_index_0d_timedelta64(self): td = timedelta(hours=1)