From 3822f990a4b4d2381d41892a9249a7c933f5b5b0 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 23 Aug 2017 11:46:50 -0700 Subject: [PATCH 01/12] Fix typos --- pandas/tseries/offsets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 29cdda5548896..80966c821b2a9 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -775,7 +775,7 @@ def _get_business_hours_by_sec(self): Return business hours in a day by seconds. """ if self._get_daytime_flag(): - # create dummy datetime to calcurate businesshours in a day + # create dummy datetime to calculate businesshours in a day dtstart = datetime(2014, 4, 1, self.start.hour, self.start.minute) until = datetime(2014, 4, 1, self.end.hour, self.end.minute) return tslib.tot_seconds(until - dtstart) @@ -810,7 +810,7 @@ def rollforward(self, dt): @apply_wraps def apply(self, other): - # calcurate here because offset is not immutable + # calculate here because offset is not immutable daytime = self._get_daytime_flag() businesshours = self._get_business_hours_by_sec() bhdelta = timedelta(seconds=businesshours) @@ -859,7 +859,7 @@ def apply(self, other): if n >= 0: bday_edge = self._prev_opening_time(other) bday_edge = bday_edge + bhdelta - # calcurate remainder + # calculate remainder bday_remain = result - bday_edge result = self._next_opening_time(other) result += bday_remain @@ -897,7 +897,7 @@ def onOffset(self, dt): def _onOffset(self, dt, businesshours): """ - Slight speedups using calcurated values + Slight speedups using calculated values """ # if self.normalize and not _is_normalized(dt): # return False From 309dd545c9d87cd42deeb5cb06ada0e617334f6d Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 23 Aug 2017 11:49:41 -0700 Subject: [PATCH 02/12] unify __repr__ and freqstr implementations --- pandas/tseries/offsets.py | 90 +++++++++++++++------------------------ 1 file changed, 35 insertions(+), 55 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 80966c821b2a9..9c2f7cff59b46 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -322,37 +322,42 @@ def _params(self): def __repr__(self): className = getattr(self, '_outputName', type(self).__name__) + + if abs(self.n) != 1: + plural = 's' + else: + plural = '' + + n_str = "" + if self.n != 1: + n_str = "%s * " % self.n + + out = '<%s' % n_str + className + plural + self._repr_attrs() + '>' + return out + + # TODO: Combine this with BusinessMixin version by defining a whitelisted + # set of attributes on each object rather than the existing behavior of + # iterating over internal ``__dict__`` + def _repr_attrs(self): exclude = set(['n', 'inc', 'normalize']) attrs = [] for attr in sorted(self.__dict__): - if ((attr == 'kwds' and len(self.kwds) == 0) or - attr.startswith('_')): + if attr.startswith('_'): continue - elif attr == 'kwds': + elif attr == 'kwds': # TODO: get rid of this kwds_new = {} for key in self.kwds: if not hasattr(self, key): kwds_new[key] = self.kwds[key] if len(kwds_new) > 0: - attrs.append('='.join((attr, repr(kwds_new)))) - else: - if attr not in exclude: - attrs.append('='.join((attr, repr(getattr(self, attr))))) + attrs.append('kwds=%s' % (kwds_new)) + elif attr not in exclude: + value = getattr(self, attr) + attrs.append('%s=%s' % (attr, value)) - plural = '' - if abs(self.n) != 1: - plural = 's' - - n_str = '' - if self.n != 1: - n_str = '{n} * '.format(n=self.n) - - attrs_str = '' + out = '' if attrs: - attrs_str = ': ' + ', '.join(attrs) - - repr_content = ''.join([n_str, className, plural, attrs_str]) - out = '<{content}>'.format(content=repr_content) + out += ': ' + ', '.join(attrs) return out @property @@ -506,8 +511,18 @@ def freqstr(self): else: fstr = code + try: + if self._offset: + fstr += self._offset_str() + except AttributeError: + # TODO: standardize `_offset` vs `offset` naming convention + pass + return fstr + def _offset_str(self): + return '' + @property def nanos(self): raise ValueError("{name} is a non-fixed frequency".format(name=self)) @@ -526,24 +541,6 @@ def _from_name(cls, suffix=None): class BusinessMixin(object): """ mixin to business types to provide related functions """ - # TODO: Combine this with DateOffset by defining a whitelisted set of - # attributes on each object rather than the existing behavior of iterating - # over internal ``__dict__`` - def __repr__(self): - className = getattr(self, '_outputName', self.__class__.__name__) - - plural = '' - if abs(self.n) != 1: - plural = 's' - - n_str = '' - if self.n != 1: - n_str = '{n} * '.format(n=self.n) - - repr_content = ''.join([n_str, className, plural, self._repr_attrs()]) - out = '<{content}>'.format(content=repr_content) - return out - def _repr_attrs(self): if self.offset: attrs = ['offset={offset!r}'.format(offset=self.offset)] @@ -594,23 +591,6 @@ def __init__(self, n=1, normalize=False, **kwds): self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - @property - def freqstr(self): - try: - code = self.rule_code - except NotImplementedError: - return repr(self) - - if self.n != 1: - fstr = '{n}{code}'.format(n=self.n, code=code) - else: - fstr = code - - if self.offset: - fstr += self._offset_str() - - return fstr - def _offset_str(self): def get_str(td): off_str = '' From 87f659b4c52206a7986753c9a76b5fb80b61b117 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 23 Aug 2017 11:53:13 -0700 Subject: [PATCH 03/12] Remove methods identical to those of parent class --- pandas/tseries/offsets.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 9c2f7cff59b46..2c9998e0142af 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -622,9 +622,6 @@ def get_str(td): else: return '+' + repr(self.offset) - def isAnchored(self): - return (self.n == 1) - @apply_wraps def apply(self, other): if isinstance(other, datetime): @@ -1358,9 +1355,6 @@ def _apply_index_days(self, i, roll): class BusinessMonthEnd(MonthOffset): """DateOffset increments between business EOM dates""" - def isAnchored(self): - return (self.n == 1) - @apply_wraps def apply(self, other): n = self.n @@ -1965,16 +1959,6 @@ class QuarterEnd(QuarterOffset): _default_startingMonth = 3 _prefix = 'Q' - def __init__(self, n=1, normalize=False, **kwds): - self.n = n - self.normalize = normalize - self.startingMonth = kwds.get('startingMonth', 3) - - self.kwds = kwds - - def isAnchored(self): - return (self.n == 1 and self.startingMonth is not None) - @apply_wraps def apply(self, other): n = self.n @@ -2010,9 +1994,6 @@ class QuarterBegin(QuarterOffset): _from_name_startingMonth = 1 _prefix = 'QS' - def isAnchored(self): - return (self.n == 1 and self.startingMonth is not None) - @apply_wraps def apply(self, other): n = self.n @@ -2640,9 +2621,6 @@ class Easter(DateOffset): """ _adjust_dst = True - def __init__(self, n=1, **kwds): - super(Easter, self).__init__(n, **kwds) - @apply_wraps def apply(self, other): currentEaster = easter(other.year) From 3d1e6f8db2b2dd471ca0138b2eb65ca6ac1930e5 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 23 Aug 2017 12:46:30 -0700 Subject: [PATCH 04/12] alias ._offset-->.offset so freqstr compat --- pandas/tseries/offsets.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 2c9998e0142af..5d7186401b82d 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -590,6 +590,7 @@ def __init__(self, n=1, normalize=False, **kwds): self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) + self._offset = self.offset # alias for backward compat def _offset_str(self): def get_str(td): @@ -686,6 +687,7 @@ def __init__(self, **kwds): kwds['end'] = self._validate_time(kwds.get('end', '17:00')) self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) + self._offset = self.offset # alias for backward compat self.start = kwds.get('start', '09:00') self.end = kwds.get('end', '17:00') @@ -955,6 +957,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) + self._offset = self.offset # alias for backward compat calendar, holidays = self.get_calendar(weekmask=weekmask, holidays=holidays, calendar=calendar) @@ -1445,6 +1448,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) + self._offset = self.offset # alias for backward compat self.cbday = CustomBusinessDay(n=self.n, normalize=normalize, weekmask=weekmask, holidays=holidays, calendar=calendar, **kwds) @@ -1505,6 +1509,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) + self._offset = self.offset # alias for backward compat self.cbday = CustomBusinessDay(n=self.n, normalize=normalize, weekmask=weekmask, holidays=holidays, calendar=calendar, **kwds) From 0f5b2a611e641dbbd98b6483bb8870e49e931269 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 23 Aug 2017 13:26:02 -0700 Subject: [PATCH 05/12] flake8 fixup --- pandas/tseries/offsets.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 5d7186401b82d..c95c51f3e71d7 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -590,7 +590,7 @@ def __init__(self, n=1, normalize=False, **kwds): self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = self.offset # alias for backward compat def _offset_str(self): def get_str(td): @@ -687,7 +687,7 @@ def __init__(self, **kwds): kwds['end'] = self._validate_time(kwds.get('end', '17:00')) self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = self.offset # alias for backward compat self.start = kwds.get('start', '09:00') self.end = kwds.get('end', '17:00') @@ -957,7 +957,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = self.offset # alias for backward compat calendar, holidays = self.get_calendar(weekmask=weekmask, holidays=holidays, calendar=calendar) @@ -1448,7 +1448,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = self.offset # alias for backward compat self.cbday = CustomBusinessDay(n=self.n, normalize=normalize, weekmask=weekmask, holidays=holidays, calendar=calendar, **kwds) @@ -1509,7 +1509,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.normalize = normalize self.kwds = kwds self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = self.offset # alias for backward compat self.cbday = CustomBusinessDay(n=self.n, normalize=normalize, weekmask=weekmask, holidays=holidays, calendar=calendar, **kwds) From c66b8421c5c53f5b8090a595ca273c353d5bb147 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 28 Aug 2017 08:21:54 -0700 Subject: [PATCH 06/12] dummy commit to force CI --- pandas/tseries/offsets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index c95c51f3e71d7..3cbb81f009b7d 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from datetime import date, datetime, timedelta from pandas.compat import range from pandas import compat From f016855d532f5abc23427ae4285e4d2919631841 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 28 Aug 2017 10:30:40 -0700 Subject: [PATCH 07/12] Dummy commit to force CI --- pandas/tseries/frequencies.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index 7f34bcaf52926..f98b359a6e680 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from datetime import timedelta from pandas.compat import long, zip from pandas import compat From 1f4b5cd60bcbade50ca4298b90f30fdc48fb06a4 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 19 Sep 2017 20:11:31 -0700 Subject: [PATCH 08/12] Make offset a property to alias _offset for backward compat --- pandas/tseries/offsets.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index c9877458cffb8..1a78dbd53855c 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -543,6 +543,11 @@ def _from_name(cls, suffix=None): class BusinessMixin(object): """ mixin to business types to provide related functions """ + @property + def offset(self): + # Alias for backward compat + return self._offset + def _repr_attrs(self): if self.offset: attrs = ['offset={offset!r}'.format(offset=self.offset)] @@ -591,8 +596,7 @@ def __init__(self, n=1, normalize=False, **kwds): self.n = int(n) self.normalize = normalize self.kwds = kwds - self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = kwds.get('offset', timedelta(0)) def _offset_str(self): def get_str(td): @@ -688,8 +692,7 @@ def __init__(self, **kwds): kwds['start'] = self._validate_time(kwds.get('start', '09:00')) kwds['end'] = self._validate_time(kwds.get('end', '17:00')) self.kwds = kwds - self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = kwds.get('offset', timedelta(0)) self.start = kwds.get('start', '09:00') self.end = kwds.get('end', '17:00') @@ -960,8 +963,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.n = int(n) self.normalize = normalize self.kwds = kwds - self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = kwds.get('offset', timedelta(0)) calendar, holidays = _get_calendar(weekmask=weekmask, holidays=holidays, @@ -1413,8 +1415,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.n = int(n) self.normalize = normalize self.kwds = kwds - self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = kwds.get('offset', timedelta(0)) calendar, holidays = _get_calendar(weekmask=weekmask, holidays=holidays, @@ -1488,8 +1489,7 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', self.n = int(n) self.normalize = normalize self.kwds = kwds - self.offset = kwds.get('offset', timedelta(0)) - self._offset = self.offset # alias for backward compat + self._offset = kwds.get('offset', timedelta(0)) # _get_calendar does validation and possible transformation # of calendar and holidays. From d1e9161b89df36d92e25ecb6f88b00563c988d8c Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Fri, 22 Sep 2017 10:39:26 -0700 Subject: [PATCH 09/12] Rename offset attribute in unpickled instance of older version --- pandas/tseries/offsets.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 1a78dbd53855c..3b4b74b4bf662 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -575,6 +575,11 @@ def __getstate__(self): def __setstate__(self, state): """Reconstruct an instance from a pickled state""" + if 'offset' in state: + # Older versions have offset attribute instead of _offset + assert '_offset' not in state, list(state.keys()) + state['_offset'] = state['offset'] + del state['offset'] self.__dict__ = state if 'weekmask' in state and 'holidays' in state: calendar, holidays = _get_calendar(weekmask=self.weekmask, From 3d3c2a67e60e18045655638028bf2a66720247f8 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Fri, 22 Sep 2017 17:03:21 -0700 Subject: [PATCH 10/12] reviewer comments, pop key, dont assert --- pandas/tseries/offsets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 3b4b74b4bf662..806d16b418b1b 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -577,9 +577,9 @@ def __setstate__(self, state): """Reconstruct an instance from a pickled state""" if 'offset' in state: # Older versions have offset attribute instead of _offset - assert '_offset' not in state, list(state.keys()) - state['_offset'] = state['offset'] - del state['offset'] + if '_offset' in state: # pragma: no cover + raise ValueError('Unexpected key `_offset`') + state['_offset'] = state.pop('offset') self.__dict__ = state if 'weekmask' in state and 'holidays' in state: calendar, holidays = _get_calendar(weekmask=self.weekmask, From c22ee249ca3644215294b56d1ef3df4ef93d2459 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 23 Sep 2017 09:06:20 -0700 Subject: [PATCH 11/12] Reduce periods for B freq to avoid OverflowError --- asv_bench/benchmarks/timeseries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asv_bench/benchmarks/timeseries.py b/asv_bench/benchmarks/timeseries.py index b7151ad2eaa99..779fc0bd20964 100644 --- a/asv_bench/benchmarks/timeseries.py +++ b/asv_bench/benchmarks/timeseries.py @@ -56,7 +56,7 @@ def setup(self): self.no_freq = self.rng7[:50000].append(self.rng7[50002:]) self.d_freq = self.rng7[:50000].append(self.rng7[50000:]) - self.rng8 = date_range(start='1/1/1700', freq='B', periods=100000) + self.rng8 = date_range(start='1/1/1700', freq='B', periods=75000) self.b_freq = self.rng8[:50000].append(self.rng8[50000:]) def time_add_timedelta(self): From e52a791fab1a98ccb9397880a0a4c496cf800990 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sat, 23 Sep 2017 09:21:28 -0700 Subject: [PATCH 12/12] docstring per reviewer request --- pandas/tseries/offsets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index a512990e37dad..ea37434e3a8d9 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -545,6 +545,7 @@ class BusinessMixin(object): @property def offset(self): + """Alias for self._offset""" # Alias for backward compat return self._offset