Skip to content

Commit 8967bc4

Browse files
chean.wei.khorchean.wei.khor
chean.wei.khor
authored and
chean.wei.khor
committed
Merge branch 'enh-consistency-interval-range' of https://github.com/weikhor/pandas into enh-consistency-interval-range
2 parents 22ab15b + a95e7ff commit 8967bc4

File tree

15 files changed

+357
-194
lines changed

15 files changed

+357
-194
lines changed

doc/source/whatsnew/v1.5.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ Other Deprecations
342342
- Deprecated allowing non-keyword arguments in :meth:`ExtensionArray.argsort` (:issue:`46134`)
343343
- Deprecated treating all-bool ``object``-dtype columns as bool-like in :meth:`DataFrame.any` and :meth:`DataFrame.all` with ``bool_only=True``, explicitly cast to bool instead (:issue:`46188`)
344344
- Deprecated behavior of method :meth:`DataFrame.quantile`, attribute ``numeric_only`` will default False. Including datetime/timedelta columns in the result (:issue:`7308`).
345+
- Deprecated :attr:`Timedelta.freq` and :attr:`Timedelta.is_populated` (:issue:`46430`)
345346
- Deprecated the ``closed`` argument in :meth:`interval_range` in favor of ``inclusive`` argument; In a future version passing ``closed`` will raise (:issue:`40245`)
346347
-
347348

pandas/_libs/tslibs/timedeltas.pxd

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ cdef bint is_any_td_scalar(object obj)
1111
cdef class _Timedelta(timedelta):
1212
cdef readonly:
1313
int64_t value # nanoseconds
14-
object freq # frequency reference
15-
bint is_populated # are my components populated
14+
bint _is_populated # are my components populated
1615
int64_t _d, _h, _m, _s, _ms, _us, _ns
1716

1817
cpdef timedelta to_pytimedelta(_Timedelta self)

pandas/_libs/tslibs/timedeltas.pyi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,7 @@ class Timedelta(timedelta):
146146
def __hash__(self) -> int: ...
147147
def isoformat(self) -> str: ...
148148
def to_numpy(self) -> np.timedelta64: ...
149+
@property
150+
def freq(self) -> None: ...
151+
@property
152+
def is_populated(self) -> bool: ...

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -826,13 +826,32 @@ cdef _to_py_int_float(v):
826826
cdef class _Timedelta(timedelta):
827827
# cdef readonly:
828828
# int64_t value # nanoseconds
829-
# object freq # frequency reference
830-
# bint is_populated # are my components populated
829+
# bint _is_populated # are my components populated
831830
# int64_t _d, _h, _m, _s, _ms, _us, _ns
832831

833832
# higher than np.ndarray and np.matrix
834833
__array_priority__ = 100
835834

835+
@property
836+
def freq(self) -> None:
837+
# GH#46430
838+
warnings.warn(
839+
"Timedelta.freq is deprecated and will be removed in a future version",
840+
FutureWarning,
841+
stacklevel=1,
842+
)
843+
return None
844+
845+
@property
846+
def is_populated(self) -> bool:
847+
# GH#46430
848+
warnings.warn(
849+
"Timedelta.is_populated is deprecated and will be removed in a future version",
850+
FutureWarning,
851+
stacklevel=1,
852+
)
853+
return self._is_populated
854+
836855
def __hash__(_Timedelta self):
837856
if self._has_ns():
838857
return hash(self.value)
@@ -881,7 +900,7 @@ cdef class _Timedelta(timedelta):
881900
"""
882901
compute the components
883902
"""
884-
if self.is_populated:
903+
if self._is_populated:
885904
return
886905

887906
cdef:
@@ -898,7 +917,7 @@ cdef class _Timedelta(timedelta):
898917
self._seconds = tds.seconds
899918
self._microseconds = tds.microseconds
900919

901-
self.is_populated = 1
920+
self._is_populated = 1
902921

903922
cpdef timedelta to_pytimedelta(_Timedelta self):
904923
"""
@@ -1389,7 +1408,7 @@ class Timedelta(_Timedelta):
13891408
# make timedelta happy
13901409
td_base = _Timedelta.__new__(cls, microseconds=int(value) // 1000)
13911410
td_base.value = value
1392-
td_base.is_populated = 0
1411+
td_base._is_populated = 0
13931412
return td_base
13941413

13951414
def __setstate__(self, state):

pandas/_libs/tslibs/tzconversion.pyx

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ from cpython.datetime cimport (
1515

1616
import_datetime()
1717

18-
from dateutil.tz import tzutc
1918
import numpy as np
2019
import pytz
2120

@@ -40,7 +39,6 @@ from pandas._libs.tslibs.np_datetime cimport (
4039
)
4140
from pandas._libs.tslibs.timezones cimport (
4241
get_dst_info,
43-
get_utcoffset,
4442
is_fixed_offset,
4543
is_tzlocal,
4644
is_utc,
@@ -194,6 +192,8 @@ timedelta-like}
194192
result_b[:] = NPY_NAT
195193

196194
for i in range(n):
195+
# This loops resembles the "Find the two best possibilities" block
196+
# in pytz's DstTZInfo.localize method.
197197
val = vals[i]
198198
if val == NPY_NAT:
199199
continue
@@ -339,27 +339,37 @@ cdef inline str _render_tstamp(int64_t val):
339339

340340
cdef ndarray[int64_t] _get_dst_hours(
341341
# vals only needed here to potential render an exception message
342-
ndarray[int64_t] vals,
342+
const int64_t[:] vals,
343343
ndarray[int64_t] result_a,
344344
ndarray[int64_t] result_b,
345345
):
346346
cdef:
347-
Py_ssize_t n = vals.shape[0]
348-
ndarray[uint8_t, cast=True] both_nat, both_eq
347+
Py_ssize_t i, n = vals.shape[0]
348+
ndarray[uint8_t, cast=True] mismatch
349349
ndarray[int64_t] delta, dst_hours
350-
ndarray trans_idx, grp, a_idx, b_idx, one_diff
350+
ndarray[intp_t] switch_idxs, trans_idx, grp, a_idx, b_idx, one_diff
351351
list trans_grp
352+
intp_t switch_idx
353+
int64_t left, right
352354

353355
dst_hours = np.empty(n, dtype=np.int64)
354356
dst_hours[:] = NPY_NAT
355357

356-
# Get the ambiguous hours (given the above, these are the hours
357-
# where result_a != result_b and neither of them are NAT)
358-
both_nat = np.logical_and(result_a != NPY_NAT, result_b != NPY_NAT)
359-
both_eq = result_a == result_b
360-
trans_idx = np.squeeze(np.nonzero(np.logical_and(both_nat, ~both_eq)))
358+
mismatch = np.zeros(n, dtype=bool)
359+
360+
for i in range(n):
361+
left = result_a[i]
362+
right = result_b[i]
363+
364+
# Get the ambiguous hours (given the above, these are the hours
365+
# where result_a != result_b and neither of them are NAT)
366+
if left != right and left != NPY_NAT and right != NPY_NAT:
367+
mismatch[i] = 1
368+
369+
trans_idx = mismatch.nonzero()[0]
370+
361371
if trans_idx.size == 1:
362-
stamp = _render_tstamp(vals[trans_idx])
372+
stamp = _render_tstamp(vals[trans_idx[0]])
363373
raise pytz.AmbiguousTimeError(
364374
f"Cannot infer dst time from {stamp} as there "
365375
"are no repeated times"
@@ -385,14 +395,14 @@ cdef ndarray[int64_t] _get_dst_hours(
385395

386396
# Find the index for the switch and pull from a for dst and b
387397
# for standard
388-
switch_idx = (delta <= 0).nonzero()[0]
389-
if switch_idx.size > 1:
398+
switch_idxs = (delta <= 0).nonzero()[0]
399+
if switch_idxs.size > 1:
390400
raise pytz.AmbiguousTimeError(
391-
f"There are {switch_idx.size} dst switches when "
401+
f"There are {switch_idxs.size} dst switches when "
392402
"there should only be 1."
393403
)
394404

395-
switch_idx = switch_idx[0] + 1 # TODO: declare type for switch_idx
405+
switch_idx = switch_idxs[0] + 1
396406
# Pull the only index and adjust
397407
a_idx = grp[:switch_idx]
398408
b_idx = grp[switch_idx:]

0 commit comments

Comments
 (0)