Skip to content

Commit 7dd22b8

Browse files
authored
REF: stronger typing in libconversion (#46742)
1 parent dafa5dd commit 7dd22b8

File tree

5 files changed

+40
-30
lines changed

5 files changed

+40
-30
lines changed

pandas/_libs/algos_common_helper.pxi.in

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def ensure_{{name}}(object arr, copy=True):
6565
if (<ndarray>arr).descr.type_num == NPY_{{c_type}}:
6666
return arr
6767
else:
68-
return arr.astype(np.{{dtype}}, copy=copy)
68+
# equiv: arr.astype(np.{{dtype}}, copy=copy)
69+
return cnp.PyArray_Cast(<ndarray>arr, cnp.NPY_{{c_type}})
6970
else:
7071
return np.array(arr, dtype=np.{{dtype}})
7172

pandas/_libs/tslib.pyx

+5-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ cpdef array_to_datetime(
424424
"""
425425
cdef:
426426
Py_ssize_t i, n = len(values)
427-
object val, py_dt, tz, tz_out = None
427+
object val, tz
428428
ndarray[int64_t] iresult
429429
ndarray[object] oresult
430430
npy_datetimestruct dts
@@ -443,6 +443,8 @@ cpdef array_to_datetime(
443443
float offset_seconds, tz_offset
444444
set out_tzoffset_vals = set()
445445
bint string_to_dts_failed
446+
datetime py_dt
447+
tzinfo tz_out = None
446448

447449
# specify error conditions
448450
assert is_raise or is_ignore or is_coerce
@@ -647,6 +649,8 @@ cpdef array_to_datetime(
647649
return result, tz_out
648650

649651

652+
@cython.wraparound(False)
653+
@cython.boundscheck(False)
650654
cdef ndarray[object] ignore_errors_out_of_bounds_fallback(ndarray[object] values):
651655
"""
652656
Fallback for array_to_datetime if an OutOfBoundsDatetime is raised

pandas/_libs/tslibs/conversion.pyx

+31-28
Original file line numberDiff line numberDiff line change
@@ -581,55 +581,62 @@ cdef _TSObject _convert_str_to_tsobject(object ts, tzinfo tz, str unit,
581581
"""
582582
cdef:
583583
npy_datetimestruct dts
584-
int out_local = 0, out_tzoffset = 0
585-
bint do_parse_datetime_string = False
584+
int out_local = 0, out_tzoffset = 0, string_to_dts_failed
585+
datetime dt
586+
int64_t ival
586587

587588
if len(ts) == 0 or ts in nat_strings:
588589
ts = NaT
590+
obj = _TSObject()
591+
obj.value = NPY_NAT
592+
obj.tzinfo = tz
593+
return obj
589594
elif ts == 'now':
590595
# Issue 9000, we short-circuit rather than going
591596
# into np_datetime_strings which returns utc
592-
ts = datetime.now(tz)
597+
dt = datetime.now(tz)
593598
elif ts == 'today':
594599
# Issue 9000, we short-circuit rather than going
595600
# into np_datetime_strings which returns a normalized datetime
596-
ts = datetime.now(tz)
601+
dt = datetime.now(tz)
597602
# equiv: datetime.today().replace(tzinfo=tz)
598603
else:
599604
string_to_dts_failed = _string_to_dts(
600605
ts, &dts, &out_local,
601606
&out_tzoffset, False
602607
)
603-
try:
604-
if not string_to_dts_failed:
608+
if not string_to_dts_failed:
609+
try:
605610
check_dts_bounds(&dts)
606611
if out_local == 1:
607612
return _create_tsobject_tz_using_offset(dts,
608613
out_tzoffset, tz)
609614
else:
610-
ts = dtstruct_to_dt64(&dts)
615+
ival = dtstruct_to_dt64(&dts)
611616
if tz is not None:
612617
# shift for _localize_tso
613-
ts = tz_localize_to_utc_single(ts, tz,
614-
ambiguous="raise")
618+
ival = tz_localize_to_utc_single(ival, tz,
619+
ambiguous="raise")
615620

616-
except OutOfBoundsDatetime:
617-
# GH#19382 for just-barely-OutOfBounds falling back to dateutil
618-
# parser will return incorrect result because it will ignore
619-
# nanoseconds
620-
raise
621+
return convert_to_tsobject(ival, tz, None, False, False)
621622

622-
except ValueError:
623-
do_parse_datetime_string = True
623+
except OutOfBoundsDatetime:
624+
# GH#19382 for just-barely-OutOfBounds falling back to dateutil
625+
# parser will return incorrect result because it will ignore
626+
# nanoseconds
627+
raise
624628

625-
if string_to_dts_failed or do_parse_datetime_string:
626-
try:
627-
ts = parse_datetime_string(ts, dayfirst=dayfirst,
628-
yearfirst=yearfirst)
629-
except (ValueError, OverflowError):
630-
raise ValueError("could not convert string to Timestamp")
629+
except ValueError:
630+
# Fall through to parse_datetime_string
631+
pass
632+
633+
try:
634+
dt = parse_datetime_string(ts, dayfirst=dayfirst,
635+
yearfirst=yearfirst)
636+
except (ValueError, OverflowError):
637+
raise ValueError("could not convert string to Timestamp")
631638

632-
return convert_to_tsobject(ts, tz, unit, dayfirst, yearfirst)
639+
return convert_datetime_to_tsobject(dt, tz)
633640

634641

635642
cdef inline check_overflows(_TSObject obj):
@@ -688,12 +695,8 @@ cdef inline void _localize_tso(_TSObject obj, tzinfo tz):
688695
Sets obj.tzinfo inplace, alters obj.dts inplace.
689696
"""
690697
cdef:
691-
ndarray[int64_t] trans
692-
int64_t[::1] deltas
693698
int64_t local_val
694-
int64_t* tdata
695-
Py_ssize_t pos, ntrans, outpos = -1
696-
str typ
699+
Py_ssize_t outpos = -1
697700

698701
assert obj.tzinfo is None
699702

pandas/_libs/tslibs/timestamps.pyx

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ cdef class _Timestamp(ABCTimestamp):
397397
elif is_datetime64_object(other):
398398
return type(self)(other) - self
399399
return NotImplemented
400+
400401
# -----------------------------------------------------------------
401402

402403
cdef int64_t _maybe_convert_value_to_local(self):

pandas/core/arrays/datetimes.py

+1
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ def _local_timestamps(self) -> np.ndarray:
812812
were timezone-naive.
813813
"""
814814
if self.tz is None or timezones.is_utc(self.tz):
815+
# Avoid the copy that would be made in tzconversion
815816
return self.asi8
816817
return tzconversion.tz_convert_from_utc(self.asi8, self.tz)
817818

0 commit comments

Comments
 (0)