Skip to content
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

DEPR: Deprecate DatetimeIndex.offset in favor of DatetimeIndex.freq #20730

Merged
merged 1 commit into from
Apr 19, 2018
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,7 @@ Deprecations
- The ``convert_datetime64`` parameter in :func:`DataFrame.to_records` has been deprecated and will be removed in a future version. The NumPy bug motivating this parameter has been resolved. The default value for this parameter has also changed from ``True`` to ``None`` (:issue:`18160`).
- :func:`Series.rolling().apply() <pandas.core.window.Rolling.apply>`, :func:`DataFrame.rolling().apply() <pandas.core.window.Rolling.apply>`,
:func:`Series.expanding().apply() <pandas.core.window.Expanding.apply>`, and :func:`DataFrame.expanding().apply() <pandas.core.window.Expanding.apply>` have deprecated passing an ``np.array`` by default. One will need to pass the new ``raw`` parameter to be explicit about what is passed (:issue:`20584`)
- ``DatetimeIndex.offset`` is deprecated. Use ``DatetimeIndex.freq`` instead (:issue:`20716`)
Copy link
Contributor

Choose a reason for hiding this comment

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

do we have a ref in api for this?

Copy link
Member

Choose a reason for hiding this comment

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

it is not mentioned in api.rst, so this is fine

Copy link
Contributor

Choose a reason for hiding this comment

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

let’s add it there

Copy link
Member

Choose a reason for hiding this comment

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

ah, no, I thought you asked about offset, which we don't need to add since we are deprecating it. freq is already correctly listed in api.rst


.. _whatsnew_0230.prior_deprecations:

Expand Down
122 changes: 69 additions & 53 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def _add_comparison_methods(cls):
_engine_type = libindex.DatetimeEngine

tz = None
offset = None
_freq = None
_comparables = ['name', 'freqstr', 'tz']
_attributes = ['name', 'freq', 'tz']

Expand Down Expand Up @@ -415,7 +415,7 @@ def __new__(cls, data=None,
subarr = data.values

if freq is None:
freq = data.offset
freq = data.freq
verify_integrity = False
else:
if data.dtype != _NS_DTYPE:
Expand Down Expand Up @@ -467,12 +467,12 @@ def __new__(cls, data=None,
if freq_infer:
inferred = subarr.inferred_freq
if inferred:
subarr.offset = to_offset(inferred)
subarr.freq = to_offset(inferred)

return subarr._deepcopy_if_needed(ref_to_data, copy)

@classmethod
def _generate(cls, start, end, periods, name, offset,
def _generate(cls, start, end, periods, name, freq,
tz=None, normalize=False, ambiguous='raise', closed=None):
if com._count_not_none(start, end, periods) != 2:
raise ValueError('Of the three parameters: start, end, and '
Expand Down Expand Up @@ -535,7 +535,7 @@ def _generate(cls, start, end, periods, name, offset,
else:
_normalized = _normalized and end.time() == _midnight

if hasattr(offset, 'delta') and offset != offsets.Day():
if hasattr(freq, 'delta') and freq != offsets.Day():
if inferred_tz is None and tz is not None:
# naive dates
if start is not None and start.tz is None:
Expand All @@ -551,11 +551,11 @@ def _generate(cls, start, end, periods, name, offset,
if end.tz is None and start.tz is not None:
end = end.tz_localize(start.tz, ambiguous=False)

if _use_cached_range(offset, _normalized, start, end):
if _use_cached_range(freq, _normalized, start, end):
index = cls._cached_range(start, end, periods=periods,
offset=offset, name=name)
freq=freq, name=name)
else:
index = _generate_regular_range(start, end, periods, offset)
index = _generate_regular_range(start, end, periods, freq)

else:

Expand All @@ -574,11 +574,11 @@ def _generate(cls, start, end, periods, name, offset,
if end.tz is None and start.tz is not None:
start = start.replace(tzinfo=None)

if _use_cached_range(offset, _normalized, start, end):
if _use_cached_range(freq, _normalized, start, end):
index = cls._cached_range(start, end, periods=periods,
offset=offset, name=name)
freq=freq, name=name)
else:
index = _generate_regular_range(start, end, periods, offset)
index = _generate_regular_range(start, end, periods, freq)

if tz is not None and getattr(index, 'tz', None) is None:
index = conversion.tz_localize_to_utc(_ensure_int64(index), tz,
Expand All @@ -596,12 +596,12 @@ def _generate(cls, start, end, periods, name, offset,
index = index[1:]
if not right_closed and len(index) and index[-1] == end:
index = index[:-1]
index = cls._simple_new(index, name=name, freq=offset, tz=tz)
index = cls._simple_new(index, name=name, freq=freq, tz=tz)
return index

@property
def _box_func(self):
return lambda x: Timestamp(x, freq=self.offset, tz=self.tz)
return lambda x: Timestamp(x, freq=self.freq, tz=self.tz)

def _convert_for_op(self, value):
""" Convert value to be insertable to ndarray """
Expand Down Expand Up @@ -647,7 +647,7 @@ def _simple_new(cls, values, name=None, freq=None, tz=None,
result = object.__new__(cls)
result._data = values
result.name = name
result.offset = freq
result._freq = freq
result._tz = timezones.maybe_get_tz(tz)
result._tz = timezones.tz_standardize(result._tz)
result._reset_identity()
Expand Down Expand Up @@ -734,7 +734,7 @@ def _has_same_tz(self, other):
return zzone == vzone

@classmethod
def _cached_range(cls, start=None, end=None, periods=None, offset=None,
def _cached_range(cls, start=None, end=None, periods=None, freq=None,
name=None):
if start is None and end is None:
# I somewhat believe this should never be raised externally
Expand All @@ -747,54 +747,54 @@ def _cached_range(cls, start=None, end=None, periods=None, offset=None,
raise TypeError(
'Must either specify period or provide both start and end.')

if offset is None:
if freq is None:
# This can't happen with external-facing code
raise TypeError('Must provide offset.')
raise TypeError('Must provide freq.')

drc = _daterange_cache
if offset not in _daterange_cache:
xdr = generate_range(offset=offset, start=_CACHE_START,
if freq not in _daterange_cache:
xdr = generate_range(offset=freq, start=_CACHE_START,
end=_CACHE_END)

arr = tools.to_datetime(list(xdr), box=False)

cachedRange = DatetimeIndex._simple_new(arr)
cachedRange.offset = offset
cachedRange.freq = freq
cachedRange = cachedRange.tz_localize(None)
cachedRange.name = None
drc[offset] = cachedRange
drc[freq] = cachedRange
else:
cachedRange = drc[offset]
cachedRange = drc[freq]

if start is None:
if not isinstance(end, Timestamp):
raise AssertionError('end must be an instance of Timestamp')

end = offset.rollback(end)
end = freq.rollback(end)

endLoc = cachedRange.get_loc(end) + 1
startLoc = endLoc - periods
elif end is None:
if not isinstance(start, Timestamp):
raise AssertionError('start must be an instance of Timestamp')

start = offset.rollforward(start)
start = freq.rollforward(start)

startLoc = cachedRange.get_loc(start)
endLoc = startLoc + periods
else:
if not offset.onOffset(start):
start = offset.rollforward(start)
if not freq.onOffset(start):
start = freq.rollforward(start)

if not offset.onOffset(end):
end = offset.rollback(end)
if not freq.onOffset(end):
end = freq.rollback(end)

startLoc = cachedRange.get_loc(start)
endLoc = cachedRange.get_loc(end) + 1

indexSlice = cachedRange[startLoc:endLoc]
indexSlice.name = name
indexSlice.offset = offset
indexSlice.freq = freq

return indexSlice

Expand Down Expand Up @@ -836,7 +836,7 @@ def __setstate__(self, state):
np.ndarray.__setstate__(data, nd_state)

self.name = own_state[0]
self.offset = own_state[1]
self.freq = own_state[1]
self._tz = timezones.tz_standardize(own_state[2])

# provide numpy < 1.7 compat
Expand Down Expand Up @@ -1184,7 +1184,7 @@ def union(self, other):
result._tz = timezones.tz_standardize(this.tz)
if (result.freq is None and
(this.freq is not None or other.freq is not None)):
result.offset = to_offset(result.inferred_freq)
result.freq = to_offset(result.inferred_freq)
return result

def to_perioddelta(self, freq):
Expand Down Expand Up @@ -1232,7 +1232,7 @@ def union_many(self, others):
this._tz = timezones.tz_standardize(tz)

if this.freq is None:
this.offset = to_offset(this.inferred_freq)
this.freq = to_offset(this.inferred_freq)
return this

def join(self, other, how='left', level=None, return_indexers=False,
Expand Down Expand Up @@ -1271,7 +1271,7 @@ def _maybe_utc_convert(self, other):
def _wrap_joined_index(self, joined, other):
name = self.name if self.name == other.name else None
if (isinstance(other, DatetimeIndex) and
self.offset == other.offset and
self.freq == other.freq and
self._can_fast_union(other)):
joined = self._shallow_copy(joined)
joined.name = name
Expand All @@ -1284,9 +1284,9 @@ def _can_fast_union(self, other):
if not isinstance(other, DatetimeIndex):
return False

offset = self.offset
freq = self.freq

if offset is None or offset != other.offset:
if freq is None or freq != other.freq:
return False

if not self.is_monotonic or not other.is_monotonic:
Expand All @@ -1306,10 +1306,10 @@ def _can_fast_union(self, other):

# Only need to "adjoin", not overlap
try:
return (right_start == left_end + offset) or right_start in left
return (right_start == left_end + freq) or right_start in left
except (ValueError):

# if we are comparing an offset that does not propagate timezones
# if we are comparing a freq that does not propagate timezones
# this will raise
return False

Expand All @@ -1329,7 +1329,7 @@ def _fast_union(self, other):
left_start, left_end = left[0], left[-1]
right_end = right[-1]

if not self.offset._should_cache():
if not self.freq._should_cache():
# concatenate dates
if left_end < right_end:
loc = right.searchsorted(left_end, side='right')
Expand All @@ -1341,7 +1341,7 @@ def _fast_union(self, other):
else:
return type(self)(start=left_start,
end=max(left_end, right_end),
freq=left.offset)
freq=left.freq)

def __iter__(self):
"""
Expand Down Expand Up @@ -1393,18 +1393,18 @@ def intersection(self, other):
result = Index.intersection(self, other)
if isinstance(result, DatetimeIndex):
if result.freq is None:
result.offset = to_offset(result.inferred_freq)
result.freq = to_offset(result.inferred_freq)
return result

elif (other.offset is None or self.offset is None or
other.offset != self.offset or
not other.offset.isAnchored() or
elif (other.freq is None or self.freq is None or
other.freq != self.freq or
not other.freq.isAnchored() or
(not self.is_monotonic or not other.is_monotonic)):
result = Index.intersection(self, other)
result = self._shallow_copy(result._values, name=result.name,
tz=result.tz, freq=None)
if result.freq is None:
result.offset = to_offset(result.inferred_freq)
result.freq = to_offset(result.inferred_freq)
return result

if len(self) == 0:
Expand Down Expand Up @@ -1729,12 +1729,28 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
@property
def freq(self):
"""get/set the frequency of the Index"""
return self.offset
return self._freq

@freq.setter
def freq(self, value):
"""get/set the frequency of the Index"""
self.offset = value
self._freq = value

@property
def offset(self):
"""get/set the frequency of the Index"""
msg = ('DatetimeIndex.offset has been deprecated and will be removed '
'in a future version; use DatetimeIndex.freq instead.')
warnings.warn(msg, FutureWarning, stacklevel=2)
return self.freq

@offset.setter
def offset(self, value):
"""get/set the frequency of the Index"""
msg = ('DatetimeIndex.offset has been deprecated and will be removed '
'in a future version; use DatetimeIndex.freq instead.')
warnings.warn(msg, FutureWarning, stacklevel=2)
self.freq = value

year = _field_accessor('year', 'Y', "The year of the datetime")
month = _field_accessor('month', 'M',
Expand Down Expand Up @@ -2525,9 +2541,9 @@ def day_name(self, locale=None):
DatetimeIndex._add_datetimelike_methods()


def _generate_regular_range(start, end, periods, offset):
if isinstance(offset, Tick):
stride = offset.nanos
def _generate_regular_range(start, end, periods, freq):
if isinstance(freq, Tick):
stride = freq.nanos
if periods is None:
b = Timestamp(start).value
# cannot just use e = Timestamp(end) + 1 because arange breaks when
Expand Down Expand Up @@ -2558,7 +2574,7 @@ def _generate_regular_range(start, end, periods, offset):
end = end.to_pydatetime()

xdr = generate_range(start=start, end=end,
periods=periods, offset=offset)
periods=periods, offset=freq)

dates = list(xdr)
# utc = len(dates) > 0 and dates[0].tzinfo is not None
Expand Down Expand Up @@ -2855,9 +2871,9 @@ def _in_range(start, end, rng_start, rng_end):
return start > rng_start and end < rng_end


def _use_cached_range(offset, _normalized, start, end):
return (offset._should_cache() and
not (offset._normalize_cache and not _normalized) and
def _use_cached_range(freq, _normalized, start, end):
return (freq._should_cache() and
not (freq._normalize_cache and not _normalized) and
_naive_in_cache_range(start, end))


Expand Down
6 changes: 3 additions & 3 deletions pandas/tests/indexes/datetimes/test_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,16 +598,16 @@ def test_datetimeindex_constructor_misc(self):
idx2 = DatetimeIndex(start=sdate, end=edate,
freq=offsets.Week(weekday=6))
assert len(idx1) == len(idx2)
assert idx1.offset == idx2.offset
assert idx1.freq == idx2.freq

idx1 = DatetimeIndex(start=sdate, end=edate, freq='QS')
idx2 = DatetimeIndex(start=sdate, end=edate,
freq=offsets.QuarterBegin(startingMonth=1))
assert len(idx1) == len(idx2)
assert idx1.offset == idx2.offset
assert idx1.freq == idx2.freq

idx1 = DatetimeIndex(start=sdate, end=edate, freq='BQ')
idx2 = DatetimeIndex(start=sdate, end=edate,
freq=offsets.BQuarterEnd(startingMonth=12))
assert len(idx1) == len(idx2)
assert idx1.offset == idx2.offset
assert idx1.freq == idx2.freq
Loading