Skip to content

Commit ecb89bd

Browse files
committed
TST: loc misbehaves when Period is at start of 3-level MultiIndex
(#20684) If `MultiIndex` is in PeriodIndex, `.loc` would raise exception with a miss match key
1 parent 96bf661 commit ecb89bd

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

doc/source/whatsnew/v1.0.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ Missing
173173

174174
MultiIndex
175175
^^^^^^^^^^
176-
177176
-
177+
- Using `.loc` with a `PeriodIndex` as a level in a `MultiIndex`, `.loc` could not raise exception when key is not matched (:issue:`20684`)
178178
-
179179

180180
I/O

pandas/_libs/tslibs/parsing.pyx

+2-4
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,8 @@ def parse_time_string(arg, freq=None, dayfirst=None, yearfirst=None):
251251
-------
252252
datetime, datetime/dateutil.parser._result, str
253253
"""
254-
if not isinstance(arg, (str, unicode)):
255-
# Note: cython recognizes `unicode` in both py2/py3, optimizes
256-
# this check into a C call.
257-
return arg
254+
if not isinstance(arg, str):
255+
raise TypeError("parse_time_string argument must be str")
258256

259257
if getattr(freq, "_typ", None) == "dateoffset":
260258
freq = freq.rule_code

pandas/tests/indexes/period/test_period.py

+34
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,40 @@ def test_insert(self):
617617
result = period_range("2017Q1", periods=4, freq="Q").insert(1, na)
618618
tm.assert_index_equal(result, expected)
619619

620+
@pytest.mark.parametrize(
621+
"msg, key",
622+
[
623+
(r"Period\('2019', 'A-DEC'\), 'foo', 'bar'", (Period(2019), "foo", "bar")),
624+
(r"Period\('2019', 'A-DEC'\), 'y1', 'bar'", (Period(2019), "y1", "bar")),
625+
(r"Period\('2019', 'A-DEC'\), 'foo', 'z1'", (Period(2019), "foo", "z1")),
626+
(r"'foo', Period\('2018', 'A-DEC'\), 'bar'", ("foo", Period(2018), "bar")),
627+
(r"'x1', Period\('2018', 'A-DEC'\), 'bar'", ("x1", Period(2018), "bar")),
628+
(r"'foo', Period\('2018', 'A-DEC'\), 'z1'", ("foo", Period(2018), "z1")),
629+
(r"'foo', 'bar', Period\('2017', 'A-DEC'\)", ("foo", "bar", Period(2017))),
630+
(r"'x2', 'bar', Period\('2017', 'A-DEC'\)", ("x2", "bar", Period(2017))),
631+
(r"'foo', 'y2', Period\('2017', 'A-DEC'\)", ("foo", "y2", Period(2017))),
632+
],
633+
)
634+
def test_contains_raise_error_if_period_index_is_in_multi_index(self, msg, key):
635+
# issue 20684
636+
"""
637+
parse_time_string return parameter if type not matched.
638+
PeriodIndex.get_loc take returned value from parse_time_string as a tuple.
639+
If first argument is Period and a tuple has 3 items,
640+
process go on not raise exception
641+
"""
642+
df = DataFrame(
643+
{
644+
"A": [Period("2019"), "x1", "x2"],
645+
"B": ["y1", Period("2018"), "y2"],
646+
"C": ["z1", "z2", Period("2017")],
647+
"V1": [1, 2, 3],
648+
"V2": [10, 20, 30],
649+
}
650+
).set_index(["A", "B", "C"])
651+
with pytest.raises(KeyError, match=msg):
652+
df.loc[key]
653+
620654

621655
def test_maybe_convert_timedelta():
622656
pi = PeriodIndex(["2000", "2001"], freq="D")

pandas/tests/tslibs/test_parsing.py

+10
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,13 @@ def test_try_parse_dates():
209209

210210
expected = np.array([parse(d, dayfirst=True) for d in arr])
211211
tm.assert_numpy_array_equal(result, expected)
212+
213+
214+
def test_parse_time_string_check_instance_type_raise_exception():
215+
# issue 20684
216+
with pytest.raises(TypeError):
217+
parse_time_string((1, 2, 3))
218+
219+
result = parse_time_string("2019")
220+
expected = (datetime(2019, 1, 1), datetime(2019, 1, 1), "year")
221+
assert result == expected

0 commit comments

Comments
 (0)