Skip to content

CLN: circular/runtime imports in tslibs #34563

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 5 commits into from
Jun 4, 2020
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
34 changes: 6 additions & 28 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ from pandas._libs.tslibs.util cimport (
is_float_object,
)

from pandas._libs.tslibs.base cimport ABCTimestamp

from pandas._libs.tslibs.ccalendar import (
MONTH_ALIASES, MONTH_TO_CAL_NUM, weekday_to_int, int_to_weekday,
)
Expand All @@ -49,7 +47,9 @@ from pandas._libs.tslibs.timezones cimport utc_pytz as UTC
from pandas._libs.tslibs.tzconversion cimport tz_convert_single

from .timedeltas cimport delta_to_nanoseconds

from .timedeltas import Timedelta
Copy link
Contributor

Choose a reason for hiding this comment

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

are we consisten about relative imports? I really don't like mixing this.

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're not, but the above line is relative so i figured this should be too since its the same module.

while we generally do absolute, i think we should move to relative for tslibs since self-containment is a big deal here

from .timestamps cimport _Timestamp
from .timestamps import Timestamp

# ---------------------------------------------------------------------
# Misc Helpers
Expand All @@ -63,7 +63,7 @@ cdef bint is_tick_object(object obj):


cdef datetime _as_datetime(datetime obj):
if isinstance(obj, ABCTimestamp):
if isinstance(obj, _Timestamp):
return obj.to_pydatetime()
return obj

Expand All @@ -72,7 +72,7 @@ cdef bint _is_normalized(datetime dt):
if dt.hour != 0 or dt.minute != 0 or dt.second != 0 or dt.microsecond != 0:
# Regardless of whether dt is datetime vs Timestamp
return False
if isinstance(dt, ABCTimestamp):
if isinstance(dt, _Timestamp):
return dt.nanosecond == 0
return True

Expand Down Expand Up @@ -107,7 +107,6 @@ def apply_wraps(func):
# not play nicely with cython class methods

def wrapper(self, other):
from pandas import Timestamp

if other is NaT:
return NaT
Expand Down Expand Up @@ -584,7 +583,6 @@ cdef class BaseOffset:
TimeStamp
Rolled timestamp if not on offset, otherwise unchanged timestamp.
"""
from pandas import Timestamp
dt = Timestamp(dt)
if not self.is_on_offset(dt):
dt = dt - type(self)(1, normalize=self.normalize, **self.kwds)
Expand All @@ -599,7 +597,6 @@ cdef class BaseOffset:
TimeStamp
Rolled timestamp if not on offset, otherwise unchanged timestamp.
"""
from pandas import Timestamp
dt = Timestamp(dt)
if not self.is_on_offset(dt):
dt = dt + type(self)(1, normalize=self.normalize, **self.kwds)
Expand Down Expand Up @@ -766,7 +763,6 @@ cdef class Tick(SingleConstructorOffset):

@property
def delta(self):
from .timedeltas import Timedelta
return self.n * Timedelta(self._nanos_inc)

@property
Expand Down Expand Up @@ -853,7 +849,7 @@ cdef class Tick(SingleConstructorOffset):

def apply(self, other):
# Timestamp can handle tz and nano sec, thus no need to use apply_wraps
if isinstance(other, ABCTimestamp):
if isinstance(other, _Timestamp):

# GH#15126
# in order to avoid a recursive
Expand All @@ -868,7 +864,6 @@ cdef class Tick(SingleConstructorOffset):
return NaT
elif is_datetime64_object(other) or PyDate_Check(other):
# PyDate_Check includes date, datetime
from pandas import Timestamp
return Timestamp(other) + self

if PyDelta_Check(other):
Expand Down Expand Up @@ -1020,7 +1015,6 @@ cdef class RelativeDeltaOffset(BaseOffset):
# bring tz back from UTC calculation
other = localize_pydatetime(other, tzinfo)

from .timestamps import Timestamp
return Timestamp(other)
else:
return other + timedelta(self.n)
Expand Down Expand Up @@ -1069,7 +1063,6 @@ cdef class RelativeDeltaOffset(BaseOffset):
if k in ["days", "hours", "minutes", "seconds", "microseconds"]
}
if timedelta_kwds:
from .timedeltas import Timedelta
delta = Timedelta(**timedelta_kwds)
index = index + (self.n * delta)
return index
Expand Down Expand Up @@ -2265,7 +2258,6 @@ cdef class SemiMonthOffset(SingleConstructorOffset):
@apply_index_wraps
def apply_index(self, dtindex):
# determine how many days away from the 1st of the month we are
from pandas import Timedelta

dti = dtindex
i8other = dtindex.asi8
Expand Down Expand Up @@ -2368,8 +2360,6 @@ cdef class SemiMonthEnd(SemiMonthOffset):
-------
result : DatetimeIndex
"""
from pandas import Timedelta

nanos = (roll % 2) * Timedelta(days=self.day_of_month).value
dtindex += nanos.astype("timedelta64[ns]")
return dtindex + Timedelta(days=-1)
Expand Down Expand Up @@ -2427,7 +2417,6 @@ cdef class SemiMonthBegin(SemiMonthOffset):
-------
result : DatetimeIndex
"""
from pandas import Timedelta
nanos = (roll % 2) * Timedelta(days=self.day_of_month - 1).value
return dtindex + nanos.astype("timedelta64[ns]")

Expand Down Expand Up @@ -2516,7 +2505,6 @@ cdef class Week(SingleConstructorOffset):
-------
result : DatetimeIndex
"""
from pandas import Timedelta
from .frequencies import get_freq_code # TODO: avoid circular import

i8other = dtindex.asi8
Expand Down Expand Up @@ -2818,8 +2806,6 @@ cdef class FY5253(FY5253Mixin):

@apply_wraps
def apply(self, other):
from pandas import Timestamp

norm = Timestamp(other).normalize()

n = self.n
Expand Down Expand Up @@ -3040,8 +3026,6 @@ cdef class FY5253Quarter(FY5253Mixin):
num_qtrs : int
tdelta : Timedelta
"""
from pandas import Timestamp, Timedelta

num_qtrs = 0

norm = Timestamp(other).tz_localize(None)
Expand Down Expand Up @@ -3072,7 +3056,6 @@ cdef class FY5253Quarter(FY5253Mixin):
@apply_wraps
def apply(self, other):
# Note: self.n == 0 is not allowed.
from pandas import Timedelta

n = self.n

Expand Down Expand Up @@ -3112,8 +3095,6 @@ cdef class FY5253Quarter(FY5253Mixin):
def year_has_extra_week(self, dt: datetime) -> bool:
# Avoid round-down errors --> normalize to get
# e.g. '370D' instead of '360D23H'
from pandas import Timestamp

norm = Timestamp(dt).normalize().tz_localize(None)

next_year_end = self._offset.rollforward(norm)
Expand Down Expand Up @@ -3592,9 +3573,6 @@ cpdef to_offset(freq):
>>> to_offset(Hour())
<Hour>
"""
# TODO: avoid runtime imports
from pandas._libs.tslibs.timedeltas import Timedelta

if freq is None:
return None

Expand Down
2 changes: 1 addition & 1 deletion pandas/_libs/tslibs/tzconversion.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ from pandas._libs.tslibs.ccalendar cimport DAY_NANOS, HOUR_NANOS
from pandas._libs.tslibs.nattype cimport NPY_NAT
from pandas._libs.tslibs.np_datetime cimport (
npy_datetimestruct, dt64_to_dtstruct)
from pandas._libs.tslibs.timedeltas cimport delta_to_nanoseconds
from pandas._libs.tslibs.timezones cimport (
get_dst_info, is_tzlocal, is_utc, get_timezone, get_utcoffset)

Expand Down Expand Up @@ -123,6 +122,7 @@ timedelta-like}
elif nonexistent == 'shift_backward':
shift_backward = True
elif PyDelta_Check(nonexistent):
from .timedeltas import delta_to_nanoseconds
Copy link
Contributor

Choose a reason for hiding this comment

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

does it make sense to move delta_to_nanoseconds even higher eg to base.pyx ?

Copy link
Member Author

Choose a reason for hiding this comment

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

ive considered this and gotten hung up on attribute lookup behavior which isnt doing optimizations that i think it should. I'd like to punt on this for now until I get that sorted out.

shift_delta = delta_to_nanoseconds(nonexistent)
elif nonexistent not in ('raise', None):
msg = ("nonexistent must be one of {'NaT', 'raise', 'shift_forward', "
Expand Down