diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index ea02e1fe865ad..a33322aebab34 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -262,6 +262,7 @@ For example: Other Deprecations ^^^^^^^^^^^^^^^^^^ - Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) +- Deprecated :func:`pandas.api.types.is_interval` and :func:`pandas.api.types.is_period`, use ``isinstance(obj, pd.Interval)`` and ``isinstance(obj, pd.Period)`` instead (:issue:`55264`) - Deprecated :func:`read_gbq` and :meth:`DataFrame.to_gbq`. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`) - Deprecated :meth:`.DataFrameGroupBy.fillna` and :meth:`.SeriesGroupBy.fillna`; use :meth:`.DataFrameGroupBy.ffill`, :meth:`.DataFrameGroupBy.bfill` for forward and backward filling or :meth:`.DataFrame.fillna` to fill with a single value (or the Series equivalents) (:issue:`55718`) - Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 0b147ab2fd0e4..8493f8bd066e0 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -65,6 +65,7 @@ from numpy cimport ( ) cnp.import_array() +from pandas._libs.interval import Interval cdef extern from "pandas/parser/pd_parser.h": @@ -228,7 +229,7 @@ def is_scalar(val: object) -> bool: # Note: PyNumber_Check check includes Decimal, Fraction, numbers.Number return (PyNumber_Check(val) or is_period_object(val) - or is_interval(val) + or isinstance(val, Interval) or is_offset_object(val)) @@ -1161,6 +1162,17 @@ cpdef bint is_decimal(object obj): cpdef bint is_interval(object obj): + import warnings + + from pandas.util._exceptions import find_stack_level + + warnings.warn( + # GH#55264 + "is_interval is deprecated and will be removed in a future version. " + "Use isinstance(obj, pd.Interval) instead.", + FutureWarning, + stacklevel=find_stack_level(), + ) return getattr(obj, "_typ", "_typ") == "interval" @@ -1172,6 +1184,17 @@ def is_period(val: object) -> bool: ------- bool """ + import warnings + + from pandas.util._exceptions import find_stack_level + + warnings.warn( + # GH#55264 + "is_period is deprecated and will be removed in a future version. " + "Use isinstance(obj, pd.Period) instead.", + FutureWarning, + stacklevel=find_stack_level(), + ) return is_period_object(val) @@ -1694,7 +1717,7 @@ def infer_dtype(value: object, skipna: bool = True) -> str: if is_period_array(values, skipna=skipna): return "period" - elif is_interval(val): + elif isinstance(val, Interval): if is_interval_array(values): return "interval" @@ -2169,7 +2192,7 @@ cpdef bint is_interval_array(ndarray values): for i in range(n): val = values[i] - if is_interval(val): + if isinstance(val, Interval): if closed is None: closed = val.closed numeric = ( @@ -2630,7 +2653,7 @@ def maybe_convert_objects(ndarray[object] objects, except (ValueError, TypeError): seen.object_ = True break - elif is_interval(val): + elif isinstance(val, Interval): if convert_non_numeric: seen.interval_ = True break diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 3cac25600bd0e..0ad652bd5aa64 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -20,7 +20,11 @@ from pandas._config import using_pyarrow_string_dtype -from pandas._libs import lib +from pandas._libs import ( + Interval, + Period, + lib, +) from pandas._libs.missing import ( NA, NAType, @@ -850,9 +854,9 @@ def infer_dtype_from_scalar(val) -> tuple[DtypeObj, Any]: elif is_complex(val): dtype = np.dtype(np.complex128) - if lib.is_period(val): + if isinstance(val, Period): dtype = PeriodDtype(freq=val.freq) - elif lib.is_interval(val): + elif isinstance(val, Interval): subtype = infer_dtype_from_scalar(val.left)[0] dtype = IntervalDtype(subtype=subtype, closed=val.closed) diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index f73e2b5512262..0982b376a27d5 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -22,6 +22,7 @@ ) from pandas._libs.tslibs import ( BaseOffset, + Period, Timedelta, Timestamp, to_offset, @@ -561,7 +562,7 @@ def _maybe_convert_i8(self, key): if scalar: # Timestamp/Timedelta key_dtype, key_i8 = infer_dtype_from_scalar(key) - if lib.is_period(key): + if isinstance(key, Period): key_i8 = key.ordinal elif isinstance(key_i8, Timestamp): key_i8 = key_i8._value diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index df7c787d2b9bf..32c8def669c21 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -1622,11 +1622,23 @@ def test_to_object_array_width(self): tm.assert_numpy_array_equal(out, expected) def test_is_period(self): - assert lib.is_period(Period("2011-01", freq="M")) - assert not lib.is_period(PeriodIndex(["2011-01"], freq="M")) - assert not lib.is_period(Timestamp("2011-01")) - assert not lib.is_period(1) - assert not lib.is_period(np.nan) + # GH#55264 + msg = "is_period is deprecated and will be removed in a future version" + with tm.assert_produces_warning(FutureWarning, match=msg): + assert lib.is_period(Period("2011-01", freq="M")) + assert not lib.is_period(PeriodIndex(["2011-01"], freq="M")) + assert not lib.is_period(Timestamp("2011-01")) + assert not lib.is_period(1) + assert not lib.is_period(np.nan) + + def test_is_interval(self): + # GH#55264 + msg = "is_interval is deprecated and will be removed in a future version" + item = Interval(1, 2) + with tm.assert_produces_warning(FutureWarning, match=msg): + assert lib.is_interval(item) + assert not lib.is_interval(pd.IntervalIndex([item])) + assert not lib.is_interval(pd.IntervalIndex([item])._engine) def test_categorical(self): # GH 8974