Skip to content

Replace is_temporal checks with Cython version #55506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pandas/_libs/lib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1649,7 +1649,7 @@ def infer_dtype(value: object, skipna: bool = True) -> str:
if seen_val is False and skipna:
return "empty"

if util.is_datetime64_object(val):
if cnp.is_datetime64_object(val):
if is_datetime64_array(values, skipna=skipna):
return "datetime64"

Expand Down Expand Up @@ -1733,7 +1733,7 @@ def infer_dtype(value: object, skipna: bool = True) -> str:


cdef bint is_timedelta(object o):
return PyDelta_Check(o) or util.is_timedelta64_object(o)
return PyDelta_Check(o) or cnp.is_timedelta64_object(o)


@cython.internal
Expand Down Expand Up @@ -2020,7 +2020,7 @@ cpdef bint is_datetime_array(ndarray values, bint skipna=True):
@cython.internal
cdef class Datetime64Validator(DatetimeValidator):
cdef bint is_value_typed(self, object value) except -1:
return util.is_datetime64_object(value)
return cnp.is_datetime64_object(value)


# Note: only python-exposed for tests
Expand All @@ -2034,7 +2034,7 @@ cpdef bint is_datetime64_array(ndarray values, bint skipna=True):
@cython.internal
cdef class AnyDatetimeValidator(DatetimeValidator):
cdef bint is_value_typed(self, object value) except -1:
return util.is_datetime64_object(value) or (
return cnp.is_datetime64_object(value) or (
PyDateTime_Check(value) and value.tzinfo is None
)

Expand Down Expand Up @@ -2617,7 +2617,7 @@ def maybe_convert_objects(ndarray[object] objects,
seen.complex_ = True
if not convert_numeric:
break
elif PyDateTime_Check(val) or util.is_datetime64_object(val):
elif PyDateTime_Check(val) or cnp.is_datetime64_object(val):

# if we have an tz's attached then return the objects
if convert_non_numeric:
Expand Down
12 changes: 6 additions & 6 deletions pandas/_libs/missing.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,17 @@ cpdef bint is_matching_na(object left, object right, bint nan_matches_none=False
and util.is_complex_object(right)
and util.is_nan(right)
)
elif util.is_datetime64_object(left):
elif cnp.is_datetime64_object(left):
return (
get_datetime64_value(left) == NPY_NAT
and util.is_datetime64_object(right)
and cnp.is_datetime64_object(right)
and get_datetime64_value(right) == NPY_NAT
and get_datetime64_unit(left) == get_datetime64_unit(right)
)
elif util.is_timedelta64_object(left):
elif cnp.is_timedelta64_object(left):
return (
get_timedelta64_value(left) == NPY_NAT
and util.is_timedelta64_object(right)
and cnp.is_timedelta64_object(right)
and get_timedelta64_value(right) == NPY_NAT
and get_datetime64_unit(left) == get_datetime64_unit(right)
)
Expand Down Expand Up @@ -169,9 +169,9 @@ cpdef bint checknull(object val, bint inf_as_na=False):
elif inf_as_na:
return val == INF or val == NEGINF
return False
elif util.is_timedelta64_object(val):
elif cnp.is_timedelta64_object(val):
return get_timedelta64_value(val) == NPY_NAT
elif util.is_datetime64_object(val):
elif cnp.is_datetime64_object(val):
return get_datetime64_value(val) == NPY_NAT
else:
return is_decimal_na(val)
Expand Down
2 changes: 1 addition & 1 deletion pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import_datetime()
cimport numpy as cnp
from numpy cimport (
int64_t,
is_datetime64_object,
ndarray,
)

Expand All @@ -47,7 +48,6 @@ import_pandas_datetime()

from pandas._libs.tslibs.strptime cimport parse_today_now
from pandas._libs.util cimport (
is_datetime64_object,
is_float_object,
is_integer_object,
)
Expand Down
2 changes: 1 addition & 1 deletion pandas/_libs/tslibs/conversion.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ from libc.math cimport log10
from numpy cimport (
int32_t,
int64_t,
is_datetime64_object,
)

cnp.import_array()
Expand Down Expand Up @@ -71,7 +72,6 @@ from pandas._libs.tslibs.tzconversion cimport (
tz_localize_to_utc_single,
)
from pandas._libs.tslibs.util cimport (
is_datetime64_object,
is_float_object,
is_integer_object,
)
Expand Down
14 changes: 7 additions & 7 deletions pandas/_libs/tslibs/nattype.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def _make_error_func(func_name: str, cls):


cdef _nat_divide_op(self, other):
if PyDelta_Check(other) or util.is_timedelta64_object(other) or other is c_NaT:
if PyDelta_Check(other) or cnp.is_timedelta64_object(other) or other is c_NaT:
return np.nan
if util.is_integer_object(other) or util.is_float_object(other):
return c_NaT
Expand Down Expand Up @@ -95,11 +95,11 @@ cdef class _NaT(datetime):
__array_priority__ = 100

def __richcmp__(_NaT self, object other, int op):
if util.is_datetime64_object(other) or PyDateTime_Check(other):
if cnp.is_datetime64_object(other) or PyDateTime_Check(other):
# We treat NaT as datetime-like for this comparison
return op == Py_NE

elif util.is_timedelta64_object(other) or PyDelta_Check(other):
elif cnp.is_timedelta64_object(other) or PyDelta_Check(other):
# We treat NaT as timedelta-like for this comparison
return op == Py_NE

Expand Down Expand Up @@ -137,7 +137,7 @@ cdef class _NaT(datetime):
return c_NaT
elif PyDelta_Check(other):
return c_NaT
elif util.is_datetime64_object(other) or util.is_timedelta64_object(other):
elif cnp.is_datetime64_object(other) or cnp.is_timedelta64_object(other):
return c_NaT

elif util.is_integer_object(other):
Expand Down Expand Up @@ -175,7 +175,7 @@ cdef class _NaT(datetime):
return c_NaT
elif PyDelta_Check(other):
return c_NaT
elif util.is_datetime64_object(other) or util.is_timedelta64_object(other):
elif cnp.is_datetime64_object(other) or cnp.is_timedelta64_object(other):
return c_NaT

elif util.is_integer_object(other):
Expand Down Expand Up @@ -1438,7 +1438,7 @@ cdef bint is_dt64nat(object val):
"""
Is this a np.datetime64 object np.datetime64("NaT").
"""
if util.is_datetime64_object(val):
if cnp.is_datetime64_object(val):
return get_datetime64_value(val) == NPY_NAT
return False

Expand All @@ -1447,6 +1447,6 @@ cdef bint is_td64nat(object val):
"""
Is this a np.timedelta64 object np.timedelta64("NaT").
"""
if util.is_timedelta64_object(val):
if cnp.is_timedelta64_object(val):
return get_timedelta64_value(val) == NPY_NAT
return False
8 changes: 4 additions & 4 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import numpy as np
cimport numpy as cnp
from numpy cimport (
int64_t,
is_datetime64_object,
ndarray,
)

Expand All @@ -36,7 +37,6 @@ from pandas._libs.properties import cache_readonly

from pandas._libs.tslibs cimport util
from pandas._libs.tslibs.util cimport (
is_datetime64_object,
is_float_object,
is_integer_object,
)
Expand Down Expand Up @@ -155,7 +155,7 @@ def apply_wraps(func):
elif (
isinstance(other, BaseOffset)
or PyDelta_Check(other)
or util.is_timedelta64_object(other)
or cnp.is_timedelta64_object(other)
):
# timedelta path
return func(self, other)
Expand Down Expand Up @@ -762,7 +762,7 @@ cdef class BaseOffset:
TypeError if `int(n)` raises
ValueError if n != int(n)
"""
if util.is_timedelta64_object(n):
if cnp.is_timedelta64_object(n):
raise TypeError(f"`n` argument must be an integer, got {type(n)}")
try:
nint = int(n)
Expand Down Expand Up @@ -1091,7 +1091,7 @@ cdef class Tick(SingleConstructorOffset):
# PyDate_Check includes date, datetime
return Timestamp(other) + self

if util.is_timedelta64_object(other) or PyDelta_Check(other):
if cnp.is_timedelta64_object(other) or PyDelta_Check(other):
return other + self.delta

raise ApplyTypeError(f"Unhandled type: {type(other).__name__}")
Expand Down
4 changes: 2 additions & 2 deletions pandas/_libs/tslibs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1821,7 +1821,7 @@ cdef class _Period(PeriodMixin):
f"Period(freq={self.freqstr})")

if (
util.is_timedelta64_object(other) and
cnp.is_timedelta64_object(other) and
get_timedelta64_value(other) == NPY_NAT
):
# i.e. np.timedelta64("nat")
Expand Down Expand Up @@ -2810,7 +2810,7 @@ class Period(_Period):
raise ValueError("Must supply freq for datetime value")
if isinstance(dt, Timestamp):
nanosecond = dt.nanosecond
elif util.is_datetime64_object(value):
elif cnp.is_datetime64_object(value):
dt = Timestamp(value)
if freq is None:
raise ValueError("Must supply freq for datetime value")
Expand Down
4 changes: 3 additions & 1 deletion pandas/_libs/tslibs/strptime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ from cpython.datetime cimport (
timedelta,
tzinfo,
)

from _strptime import (
TimeRE as _TimeRE,
_getlang,
Expand All @@ -42,6 +43,7 @@ import pytz
cimport numpy as cnp
from numpy cimport (
int64_t,
is_datetime64_object,
ndarray,
)

Expand Down Expand Up @@ -69,9 +71,9 @@ from pandas._libs.tslibs.np_datetime cimport (
import_pandas_datetime()

from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime

from pandas._libs.tslibs.timestamps cimport _Timestamp
from pandas._libs.util cimport (
is_datetime64_object,
is_float_object,
is_integer_object,
)
Expand Down
4 changes: 2 additions & 2 deletions pandas/_libs/tslibs/timedeltas.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import numpy as np
cimport numpy as cnp
from numpy cimport (
int64_t,
is_datetime64_object,
is_timedelta64_object,
ndarray,
)

Expand Down Expand Up @@ -80,10 +82,8 @@ from pandas._libs.tslibs.np_datetime import (
from pandas._libs.tslibs.offsets cimport is_tick_object
from pandas._libs.tslibs.util cimport (
is_array,
is_datetime64_object,
is_float_object,
is_integer_object,
is_timedelta64_object,
)

from pandas._libs.tslibs.fields import (
Expand Down
2 changes: 1 addition & 1 deletion pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import numpy as np
cimport numpy as cnp
from numpy cimport (
int64_t,
is_datetime64_object,
ndarray,
uint8_t,
)
Expand Down Expand Up @@ -65,7 +66,6 @@ from pandas._libs.tslibs.dtypes cimport (
)
from pandas._libs.tslibs.util cimport (
is_array,
is_datetime64_object,
is_integer_object,
)

Expand Down
35 changes: 3 additions & 32 deletions pandas/_libs/tslibs/util.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ cdef extern from "Python.h":
from numpy cimport (
float64_t,
int64_t,
is_timedelta64_object,
)


Expand All @@ -51,7 +52,7 @@ cdef inline int64_t get_nat() noexcept:
# --------------------------------------------------------------------
# Type Checking

cdef inline bint is_integer_object(object obj) noexcept nogil:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We previously declared is_timedelta64_object / is_datetime64_object to be nogil, which cascaded through the rest of the functions in this pxd file. However, the upstream function is not considered nogil, with some discussion coming back to here:

numpy/numpy#16266 (comment)

I think its a mistake for any of the functions in this module that touch CPython objects to be declared nogil, unless something more recent in CPython has declared these functions as such (haven't looked)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just rip this out since we're using the cnp version everywhere?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh never mind, i see you did that where relevant below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are talking about the nogil right? Yea I did the minimum required for this PR. There are still other functions in util.pxd where it should probably be removed

cdef inline bint is_integer_object(object obj) noexcept:
"""
Cython equivalent of

Expand Down Expand Up @@ -121,40 +122,10 @@ cdef inline bint is_bool_object(object obj) noexcept nogil:
PyObject_TypeCheck(obj, &PyBoolArrType_Type))


cdef inline bint is_real_number_object(object obj) noexcept nogil:
cdef inline bint is_real_number_object(object obj) noexcept:
return is_bool_object(obj) or is_integer_object(obj) or is_float_object(obj)


cdef inline bint is_timedelta64_object(object obj) noexcept nogil:
"""
Cython equivalent of `isinstance(val, np.timedelta64)`

Parameters
----------
val : object

Returns
-------
is_timedelta64 : bool
"""
return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)


cdef inline bint is_datetime64_object(object obj) noexcept nogil:
"""
Cython equivalent of `isinstance(val, np.datetime64)`

Parameters
----------
val : object

Returns
-------
is_datetime64 : bool
"""
return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)


cdef inline bint is_array(object val) noexcept:
"""
Cython equivalent of `isinstance(val, np.ndarray)`
Expand Down