pydata / xarray

N-D labeled arrays and datasets in Python
https://xarray.dev
Apache License 2.0
3.62k stars 1.08k forks source link

Many tests fail: AttributeError: 'cftime._cftime.DatetimeJulian' object has no attribute 'daysinmonth' #7467

Closed yurivict closed 1 year ago

yurivict commented 1 year ago

What happened?

There are many failures due to missing 'daysinmonth' attribute:

___________________________________________________________________________________ test_infer_freq[360_day-3QS-DEC] ____________________________________________________________________________________

freq = '3QS-DEC', calendar = '360_day'

    @requires_cftime
    @pytest.mark.parametrize(
        "freq",
        [
            "300AS-JAN",
            "A-DEC",
            "AS-JUL",
            "2AS-FEB",
            "Q-NOV",
            "3QS-DEC",
            "MS",
            "4M",
            "7D",
            "D",
            "30H",
            "5T",
            "40S",
        ],
    )
    @pytest.mark.parametrize("calendar", _CFTIME_CALENDARS)
    def test_infer_freq(freq, calendar):
        indx = xr.cftime_range("2000-01-01", periods=3, freq=freq, calendar=calendar)
>       out = xr.infer_freq(indx)

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/tests/test_cftimeindex.py:1334: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:98: in infer_freq
    return inferer.get_freq()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:133: in get_freq
    return self._infer_daily_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:158: in _infer_daily_rule
    quartely_rule = self._get_quartely_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:194: in _get_quartely_rule
    return {"cs": "QS", "ce": "Q"}.get(month_anchor_check(self.index))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dates = <[AttributeError("'cftime._cftime.Datetime360Day' object has no attribute 'daysinmonth'") raised in repr()] CFTimeIndex object at 0xc989846a0>

    def month_anchor_check(dates):
        """Return the monthly offset string.

        Return "cs" if all dates are the first days of the month,
        "ce" if all dates are the last day of the month,
        None otherwise.

        Replicated pandas._libs.tslibs.resolution.month_position_check
        but without business offset handling.
        """
        calendar_end = True
        calendar_start = True

        for date in dates:
            if calendar_start:
                calendar_start &= date.day == 1

            if calendar_end:
>               cal = date.day == date.daysinmonth
E               AttributeError: 'cftime._cftime.Datetime360Day' object has no attribute 'daysinmonth'

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:262: AttributeError
____________________________________________________________________________________ test_infer_freq[365_day-A-DEC] _____________________________________________________________________________________

freq = 'A-DEC', calendar = '365_day'

    @requires_cftime
    @pytest.mark.parametrize(
        "freq",
        [
            "300AS-JAN",
            "A-DEC",
            "AS-JUL",
            "2AS-FEB",
            "Q-NOV",
            "3QS-DEC",
            "MS",
            "4M",
            "7D",
            "D",
            "30H",
            "5T",
            "40S",
        ],
    )
    @pytest.mark.parametrize("calendar", _CFTIME_CALENDARS)
    def test_infer_freq(freq, calendar):
        indx = xr.cftime_range("2000-01-01", periods=3, freq=freq, calendar=calendar)
>       out = xr.infer_freq(indx)

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/tests/test_cftimeindex.py:1334: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:98: in infer_freq
    return inferer.get_freq()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:133: in get_freq
    return self._infer_daily_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:151: in _infer_daily_rule
    annual_rule = self._get_annual_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:185: in _get_annual_rule
    return {"cs": "AS", "ce": "A"}.get(month_anchor_check(self.index))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dates = <[AttributeError("'cftime._cftime.DatetimeNoLeap' object has no attribute 'daysinmonth'") raised in repr()] CFTimeIndex object at 0xc9b802040>

    def month_anchor_check(dates):
        """Return the monthly offset string.

        Return "cs" if all dates are the first days of the month,
        "ce" if all dates are the last day of the month,
        None otherwise.

        Replicated pandas._libs.tslibs.resolution.month_position_check
        but without business offset handling.
        """
        calendar_end = True
        calendar_start = True

        for date in dates:
            if calendar_start:
                calendar_start &= date.day == 1

            if calendar_end:
>               cal = date.day == date.daysinmonth
E               AttributeError: 'cftime._cftime.DatetimeNoLeap' object has no attribute 'daysinmonth'

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:262: AttributeError
_____________________________________________________________________________________ test_infer_freq[julian-Q-NOV] _____________________________________________________________________________________

freq = 'Q-NOV', calendar = 'julian'

    @requires_cftime
    @pytest.mark.parametrize(
        "freq",
        [
            "300AS-JAN",
            "A-DEC",
            "AS-JUL",
            "2AS-FEB",
            "Q-NOV",
            "3QS-DEC",
            "MS",
            "4M",
            "7D",
            "D",
            "30H",
            "5T",
            "40S",
        ],
    )
    @pytest.mark.parametrize("calendar", _CFTIME_CALENDARS)
    def test_infer_freq(freq, calendar):
        indx = xr.cftime_range("2000-01-01", periods=3, freq=freq, calendar=calendar)
>       out = xr.infer_freq(indx)

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/tests/test_cftimeindex.py:1334: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:98: in infer_freq
    return inferer.get_freq()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:133: in get_freq
    return self._infer_daily_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:158: in _infer_daily_rule
    quartely_rule = self._get_quartely_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:194: in _get_quartely_rule
    return {"cs": "QS", "ce": "Q"}.get(month_anchor_check(self.index))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dates = <[AttributeError("'cftime._cftime.DatetimeJulian' object has no attribute 'daysinmonth'") raised in repr()] CFTimeIndex object at 0xc9a4c14c0>

    def month_anchor_check(dates):
        """Return the monthly offset string.

        Return "cs" if all dates are the first days of the month,
        "ce" if all dates are the last day of the month,
        None otherwise.

        Replicated pandas._libs.tslibs.resolution.month_position_check
        but without business offset handling.
        """
        calendar_end = True
        calendar_start = True

        for date in dates:
            if calendar_start:
                calendar_start &= date.day == 1

            if calendar_end:
>               cal = date.day == date.daysinmonth
E               AttributeError: 'cftime._cftime.DatetimeJulian' object has no attribute 'daysinmonth'

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:262: AttributeError
_____________________________________________________________________________________ test_infer_freq[all_leap-MS] ______________________________________________________________________________________

freq = 'MS', calendar = 'all_leap'

    @requires_cftime
    @pytest.mark.parametrize(
        "freq",
        [
            "300AS-JAN",
            "A-DEC",
            "AS-JUL",
            "2AS-FEB",
            "Q-NOV",
            "3QS-DEC",
            "MS",
            "4M",
            "7D",
            "D",
            "30H",
            "5T",
            "40S",
        ],
    )
    @pytest.mark.parametrize("calendar", _CFTIME_CALENDARS)
    def test_infer_freq(freq, calendar):
        indx = xr.cftime_range("2000-01-01", periods=3, freq=freq, calendar=calendar)
>       out = xr.infer_freq(indx)

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/tests/test_cftimeindex.py:1334: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:98: in infer_freq
    return inferer.get_freq()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:133: in get_freq
    return self._infer_daily_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:166: in _infer_daily_rule
    monthly_rule = self._get_monthly_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:200: in _get_monthly_rule
    return {"cs": "MS", "ce": "M"}.get(month_anchor_check(self.index))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dates = <[AttributeError("'cftime._cftime.DatetimeAllLeap' object has no attribute 'daysinmonth'") raised in repr()] CFTimeIndex object at 0xc9b8022b0>

    def month_anchor_check(dates):
        """Return the monthly offset string.

        Return "cs" if all dates are the first days of the month,
        "ce" if all dates are the last day of the month,
        None otherwise.

        Replicated pandas._libs.tslibs.resolution.month_position_check
        but without business offset handling.
        """
        calendar_end = True
        calendar_start = True

        for date in dates:
            if calendar_start:
                calendar_start &= date.day == 1

            if calendar_end:
>               cal = date.day == date.daysinmonth
E               AttributeError: 'cftime._cftime.DatetimeAllLeap' object has no attribute 'daysinmonth'

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:262: AttributeError
_____________________________________________________________________________ test_cftimeindex_calendar_repr[julian-julian] _____________________________________________________________________________

calendar = 'julian', expected = 'julian'

    @requires_cftime
    @pytest.mark.parametrize(
        ("calendar", "expected"),
        [
            ("noleap", "noleap"),
            ("365_day", "noleap"),
            ("360_day", "360_day"),
            ("julian", "julian"),
            ("gregorian", standard_or_gregorian),
            ("standard", standard_or_gregorian),
            ("proleptic_gregorian", "proleptic_gregorian"),
        ],
    )
    def test_cftimeindex_calendar_repr(calendar, expected):
        """Test that cftimeindex has calendar property in repr."""
        index = xr.cftime_range(start="2000", periods=3, calendar=calendar)
>       repr_str = index.__repr__()

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/tests/test_cftimeindex.py:1012: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/cftimeindex.py:356: in __repr__
    attrs_str = format_attrs(self)
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/cftimeindex.py:276: in format_attrs
    "freq": f"'{index.freq}'" if len(index) >= 3 else None,
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/cftimeindex.py:708: in freq
    return infer_freq(self)
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:98: in infer_freq
    return inferer.get_freq()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:133: in get_freq
    return self._infer_daily_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:151: in _infer_daily_rule
    annual_rule = self._get_annual_rule()
/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:185: in _get_annual_rule
    return {"cs": "AS", "ce": "A"}.get(month_anchor_check(self.index))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dates = <[AttributeError("'cftime._cftime.DatetimeJulian' object has no attribute 'daysinmonth'") raised in repr()] CFTimeIndex object at 0xc9a4d6e50>

    def month_anchor_check(dates):
        """Return the monthly offset string.

        Return "cs" if all dates are the first days of the month,
        "ce" if all dates are the last day of the month,
        None otherwise.

        Replicated pandas._libs.tslibs.resolution.month_position_check
        but without business offset handling.
        """
        calendar_end = True
        calendar_start = True

        for date in dates:
            if calendar_start:
                calendar_start &= date.day == 1

            if calendar_end:
>               cal = date.day == date.daysinmonth
E               AttributeError: 'cftime._cftime.DatetimeJulian' object has no attribute 'daysinmonth'

/usr/ports/devel/py-xarray/work-py39/xarray-2023.1.0/xarray/coding/frequencies.py:262: AttributeError

Version: 2023.1.0 Python-3.9 FreeBSD 13.1

What did you expect to happen?

No response

Minimal Complete Verifiable Example

No response

MVCE confirmation

Relevant log output

No response

Anything else we need to know?

No response

Environment

spencerkclark commented 1 year ago

@yurivict could you show the output of xarray.show_versions()? I suspect you are using an old version of cftime. Xarray requires a minimum version of 1.5.

spencerkclark commented 1 year ago

(Obviously the above comment only applies if cftime installed; technically cftime is an optional dependency)

yurivict commented 1 year ago
$ pkg info | grep cftime
py39-cftime-1.0.3.4_1          Time-handling functionality from netcdf4-python

requirements.txt doesn't have cftime in it.

yurivict commented 1 year ago

(Obviously the above comment only applies if cftime installed; technically cftime is an optional dependency)

But if it breaks when a wrong cftime version is present you probably should check its version and not use it or fail when it is too old.

mathause commented 1 year ago

I think the problem is that there is no way to pin optional dependecies in conda. I understand your frustration but it's not practical to explicitly test for all of this in the code.

dcherian commented 1 year ago

Oh apparently you can place constraints on optional packages: https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#run-constrained

Seems like we just need to update the meta.yaml in the feedstock appropriately.