Description
Hi,
While playing with the frequency module, I might have found a bug with the function _period_str_to_code:
the function didn't return the code 8000 for the frequency string "minute", yet it works for frequency strings as 'T', 'Min', 'min'...
Here's the code to reproduce the 'bug':
>>> from pandas.tseries.frequencies import _period_str_to_code
>>> _period_str_to_code('Min')
8000
>>> _period_str_to_code('T')
8000
>>> _period_str_to_code('minute')
sys:1: FutureWarning: Freq "MINUTE" is deprecated, use "Min" as alternative.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "***/site-packages/pandas/tseries/frequencies.py", line 813, in _period_str_to_code
return _period_code_map[alias]
KeyError: 'Min'
(in pandas/tseries/frequencies.py line 783 to line 813)
It appears that 'minute' is converted into the alias 'Min' during the function __period_str_to_code_ (line 807).
'Min' is then used as a key in the dictionnary __period_code_map, but this dictionnary doesn't hold any value for this key (line 813).
Indeed, the key 'Min' is stored in the dictionnary __lite_rule_alias where it indexes the value 'T' (the correct frequency string for minutes).
This particuliar situation could be solved by transforming the return of the function __period_str_to_code_ by using a recursive call which allows to 'safely' handle the converted frequency string (_period_str_to_code('minute') > 'Min' > _period_str_to_code('Min') > 8000).
The conversion from 'Min' to 'T' occures line 799, and the conversion from 'T' to 8000 occures line 804.
But I'm not sure of the implication of such a recursive call (performance impact, possibility of an 'infinite' recursive call in some situation, and so on).
Here is the function with a recursive call (change in pandas/tseries/frequencies.py line 813):
def _period_str_to_code(freqstr):
# hack
if freqstr in _rule_aliases:
new = _rule_aliases[freqstr]
warnings.warn(_LEGACY_FREQ_WARNING.format(freqstr, new),
FutureWarning, stacklevel=3)
freqstr = new
freqstr = _lite_rule_alias.get(freqstr, freqstr)
if freqstr not in _dont_uppercase:
lower = freqstr.lower()
if lower in _rule_aliases:
new = _rule_aliases[lower]
warnings.warn(_LEGACY_FREQ_WARNING.format(lower, new),
FutureWarning, stacklevel=3)
freqstr = new
freqstr = _lite_rule_alias.get(lower, freqstr)
try:
if freqstr not in _dont_uppercase:
freqstr = freqstr.upper()
return _period_code_map[freqstr]
except KeyError:
try:
alias = _period_alias_dict[freqstr]
warnings.warn(_LEGACY_FREQ_WARNING.format(freqstr, alias),
FutureWarning, stacklevel=3)
except KeyError:
raise ValueError("Unknown freqstr: %s" % freqstr)
return _period_str_to_code(alias)