Skip to content

Commit 9c1bae4

Browse files
committed
CLN/ENH: Stop instantiating all offsets on load.
Use a more flexible lookup based on prefix then delegate creation to class' `from_name()` method. Totally get rid of hasOffsetName (not necessary). Finally, make some inheriting go on to simplify things.
1 parent 6060e5a commit 9c1bae4

File tree

4 files changed

+300
-360
lines changed

4 files changed

+300
-360
lines changed

Diff for: doc/source/release.rst

+4
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ See :ref:`Internal Refactoring<whatsnew_0130.refactoring>`
394394
bs4/lxml (:issue:`4770`).
395395
- Removed the ``keep_internal`` keyword parameter in
396396
``pandas/core/groupby.py`` because it wasn't being used (:issue:`5102`).
397+
- Base ``DateOffsets`` are no longer all instantiated on importing pandas,
398+
instead they are generated and cached on the fly. The internal
399+
representation and handling of DateOffsets has also been clarified.
400+
(:issue:`5189`, related :issue:`5004`)
397401

398402
.. _release.bug_fixes-0.13.0:
399403

Diff for: pandas/tseries/frequencies.py

+28-179
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import pandas.core.common as com
1313
import pandas.lib as lib
1414
import pandas.tslib as tslib
15-
from pandas import _np_version_under1p7
1615

1716

1817
class FreqGroup(object):
@@ -125,162 +124,15 @@ def _get_freq_str(base, mult=1):
125124
MonthEnd, BMonthBegin, BMonthEnd,
126125
QuarterBegin, QuarterEnd, BQuarterBegin,
127126
BQuarterEnd, YearBegin, YearEnd,
128-
BYearBegin, BYearEnd,
127+
BYearBegin, BYearEnd, _make_offset
129128
)
130129
try:
131130
cday = CDay()
132131
except NotImplementedError:
133132
cday = None
134133

135-
_offset_map = {
136-
'D': Day(),
137-
'C': cday,
138-
'B': BDay(),
139-
'H': Hour(),
140-
'T': Minute(),
141-
'S': Second(),
142-
'L': Milli(),
143-
'U': Micro(),
144-
None: None,
145-
146-
# Monthly - Calendar
147-
'M': MonthEnd(),
148-
'MS': MonthBegin(),
149-
150-
# Monthly - Business
151-
'BM': BMonthEnd(),
152-
'BMS': BMonthBegin(),
153-
154-
# Annual - Calendar
155-
'A-JAN': YearEnd(month=1),
156-
'A-FEB': YearEnd(month=2),
157-
'A-MAR': YearEnd(month=3),
158-
'A-APR': YearEnd(month=4),
159-
'A-MAY': YearEnd(month=5),
160-
'A-JUN': YearEnd(month=6),
161-
'A-JUL': YearEnd(month=7),
162-
'A-AUG': YearEnd(month=8),
163-
'A-SEP': YearEnd(month=9),
164-
'A-OCT': YearEnd(month=10),
165-
'A-NOV': YearEnd(month=11),
166-
'A-DEC': YearEnd(month=12),
167-
168-
# Annual - Calendar (start)
169-
'AS-JAN': YearBegin(month=1),
170-
'AS-FEB': YearBegin(month=2),
171-
'AS-MAR': YearBegin(month=3),
172-
'AS-APR': YearBegin(month=4),
173-
'AS-MAY': YearBegin(month=5),
174-
'AS-JUN': YearBegin(month=6),
175-
'AS-JUL': YearBegin(month=7),
176-
'AS-AUG': YearBegin(month=8),
177-
'AS-SEP': YearBegin(month=9),
178-
'AS-OCT': YearBegin(month=10),
179-
'AS-NOV': YearBegin(month=11),
180-
'AS-DEC': YearBegin(month=12),
181-
182-
# Annual - Business
183-
'BA-JAN': BYearEnd(month=1),
184-
'BA-FEB': BYearEnd(month=2),
185-
'BA-MAR': BYearEnd(month=3),
186-
'BA-APR': BYearEnd(month=4),
187-
'BA-MAY': BYearEnd(month=5),
188-
'BA-JUN': BYearEnd(month=6),
189-
'BA-JUL': BYearEnd(month=7),
190-
'BA-AUG': BYearEnd(month=8),
191-
'BA-SEP': BYearEnd(month=9),
192-
'BA-OCT': BYearEnd(month=10),
193-
'BA-NOV': BYearEnd(month=11),
194-
'BA-DEC': BYearEnd(month=12),
195-
196-
# Annual - Business (Start)
197-
'BAS-JAN': BYearBegin(month=1),
198-
'BAS-FEB': BYearBegin(month=2),
199-
'BAS-MAR': BYearBegin(month=3),
200-
'BAS-APR': BYearBegin(month=4),
201-
'BAS-MAY': BYearBegin(month=5),
202-
'BAS-JUN': BYearBegin(month=6),
203-
'BAS-JUL': BYearBegin(month=7),
204-
'BAS-AUG': BYearBegin(month=8),
205-
'BAS-SEP': BYearBegin(month=9),
206-
'BAS-OCT': BYearBegin(month=10),
207-
'BAS-NOV': BYearBegin(month=11),
208-
'BAS-DEC': BYearBegin(month=12),
209-
210-
# Quarterly - Calendar
211-
# 'Q' : QuarterEnd(startingMonth=3),
212-
'Q-JAN': QuarterEnd(startingMonth=1),
213-
'Q-FEB': QuarterEnd(startingMonth=2),
214-
'Q-MAR': QuarterEnd(startingMonth=3),
215-
'Q-APR': QuarterEnd(startingMonth=4),
216-
'Q-MAY': QuarterEnd(startingMonth=5),
217-
'Q-JUN': QuarterEnd(startingMonth=6),
218-
'Q-JUL': QuarterEnd(startingMonth=7),
219-
'Q-AUG': QuarterEnd(startingMonth=8),
220-
'Q-SEP': QuarterEnd(startingMonth=9),
221-
'Q-OCT': QuarterEnd(startingMonth=10),
222-
'Q-NOV': QuarterEnd(startingMonth=11),
223-
'Q-DEC': QuarterEnd(startingMonth=12),
224-
225-
# Quarterly - Calendar (Start)
226-
'QS': QuarterBegin(startingMonth=1),
227-
'QS-JAN': QuarterBegin(startingMonth=1),
228-
'QS-FEB': QuarterBegin(startingMonth=2),
229-
'QS-MAR': QuarterBegin(startingMonth=3),
230-
'QS-APR': QuarterBegin(startingMonth=4),
231-
'QS-MAY': QuarterBegin(startingMonth=5),
232-
'QS-JUN': QuarterBegin(startingMonth=6),
233-
'QS-JUL': QuarterBegin(startingMonth=7),
234-
'QS-AUG': QuarterBegin(startingMonth=8),
235-
'QS-SEP': QuarterBegin(startingMonth=9),
236-
'QS-OCT': QuarterBegin(startingMonth=10),
237-
'QS-NOV': QuarterBegin(startingMonth=11),
238-
'QS-DEC': QuarterBegin(startingMonth=12),
239-
240-
# Quarterly - Business
241-
'BQ-JAN': BQuarterEnd(startingMonth=1),
242-
'BQ-FEB': BQuarterEnd(startingMonth=2),
243-
'BQ-MAR': BQuarterEnd(startingMonth=3),
244-
245-
'BQ': BQuarterEnd(startingMonth=12),
246-
'BQ-APR': BQuarterEnd(startingMonth=4),
247-
'BQ-MAY': BQuarterEnd(startingMonth=5),
248-
'BQ-JUN': BQuarterEnd(startingMonth=6),
249-
'BQ-JUL': BQuarterEnd(startingMonth=7),
250-
'BQ-AUG': BQuarterEnd(startingMonth=8),
251-
'BQ-SEP': BQuarterEnd(startingMonth=9),
252-
'BQ-OCT': BQuarterEnd(startingMonth=10),
253-
'BQ-NOV': BQuarterEnd(startingMonth=11),
254-
'BQ-DEC': BQuarterEnd(startingMonth=12),
255-
256-
# Quarterly - Business (Start)
257-
'BQS-JAN': BQuarterBegin(startingMonth=1),
258-
'BQS': BQuarterBegin(startingMonth=1),
259-
'BQS-FEB': BQuarterBegin(startingMonth=2),
260-
'BQS-MAR': BQuarterBegin(startingMonth=3),
261-
'BQS-APR': BQuarterBegin(startingMonth=4),
262-
'BQS-MAY': BQuarterBegin(startingMonth=5),
263-
'BQS-JUN': BQuarterBegin(startingMonth=6),
264-
'BQS-JUL': BQuarterBegin(startingMonth=7),
265-
'BQS-AUG': BQuarterBegin(startingMonth=8),
266-
'BQS-SEP': BQuarterBegin(startingMonth=9),
267-
'BQS-OCT': BQuarterBegin(startingMonth=10),
268-
'BQS-NOV': BQuarterBegin(startingMonth=11),
269-
'BQS-DEC': BQuarterBegin(startingMonth=12),
270-
271-
# Weekly
272-
'W-MON': Week(weekday=0),
273-
'W-TUE': Week(weekday=1),
274-
'W-WED': Week(weekday=2),
275-
'W-THU': Week(weekday=3),
276-
'W-FRI': Week(weekday=4),
277-
'W-SAT': Week(weekday=5),
278-
'W-SUN': Week(weekday=6),
279-
280-
}
281-
282-
if not _np_version_under1p7:
283-
_offset_map['N'] = Nano()
134+
#: cache of previously seen offsets
135+
_offset_map = {}
284136

285137
_offset_to_period_map = {
286138
'WEEKDAY': 'D',
@@ -386,15 +238,6 @@ def get_period_alias(offset_str):
386238
_legacy_reverse_map = dict((v, k) for k, v in
387239
reversed(sorted(compat.iteritems(_rule_aliases))))
388240

389-
# for helping out with pretty-printing and name-lookups
390-
391-
_offset_names = {}
392-
for name, offset in compat.iteritems(_offset_map):
393-
if offset is None:
394-
continue
395-
offset.name = name
396-
_offset_names[offset] = name
397-
398241

399242
def inferTimeRule(index):
400243
from pandas.tseries.index import DatetimeIndex
@@ -513,22 +356,21 @@ def get_offset(name):
513356
else:
514357
if name in _rule_aliases:
515358
name = _rule_aliases[name]
516-
517-
offset = _offset_map.get(name)
518-
519-
if offset is not None:
520-
return offset
521-
else:
522-
raise ValueError('Bad rule name requested: %s.' % name)
359+
try:
360+
if name not in _offset_map:
361+
# generate and cache offset
362+
offset = _make_offset(name)
363+
_offset_map[name] = offset
364+
return _offset_map[name]
365+
except (ValueError, TypeError, KeyError):
366+
# bad prefix or suffix
367+
pass
368+
raise ValueError('Bad rule name requested: %s.' % name)
523369

524370

525371
getOffset = get_offset
526372

527373

528-
def hasOffsetName(offset):
529-
return offset in _offset_names
530-
531-
532374
def get_offset_name(offset):
533375
"""
534376
Return rule name associated with a DateOffset object
@@ -537,19 +379,26 @@ def get_offset_name(offset):
537379
--------
538380
get_offset_name(BMonthEnd(1)) --> 'EOM'
539381
"""
540-
name = _offset_names.get(offset)
541-
542-
if name is not None:
543-
return name
544-
else:
382+
if offset is None:
383+
raise ValueError("Offset can't be none!")
384+
# Hack because this is what it did before...
385+
if isinstance(offset, BDay):
386+
if offset.n != 1:
387+
raise ValueError('Bad rule given: %s.' % 'BusinessDays')
388+
else:
389+
return offset.rule_code
390+
try:
391+
return offset.freqstr
392+
except AttributeError:
393+
# Bad offset, give useful error.
545394
raise ValueError('Bad rule given: %s.' % offset)
546395

547396

548397
def get_legacy_offset_name(offset):
549398
"""
550399
Return the pre pandas 0.8.0 name for the date offset
551400
"""
552-
name = _offset_names.get(offset)
401+
name = offset.name
553402
return _legacy_reverse_map.get(name, name)
554403

555404
get_offset_name = get_offset_name
@@ -652,7 +501,7 @@ def _period_alias_dictionary():
652501
L_aliases = ["L", "MS", "MILLISECOND", "MILLISECONDLY"]
653502
U_aliases = ["U", "US", "MICROSECOND", "MICROSECONDLY"]
654503
N_aliases = ["N", "NS", "NANOSECOND", "NANOSECONDLY"]
655-
504+
656505
for k in M_aliases:
657506
alias_dict[k] = 'M'
658507

@@ -679,7 +528,7 @@ def _period_alias_dictionary():
679528

680529
for k in N_aliases:
681530
alias_dict[k] = 'N'
682-
531+
683532
A_prefixes = ["A", "Y", "ANN", "ANNUAL", "ANNUALLY", "YR", "YEAR",
684533
"YEARLY"]
685534

0 commit comments

Comments
 (0)