diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 149d618c4a621..b122a24ee5450 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1205,6 +1205,7 @@ Indexing ^^^^^^^^ - The traceback from a ``KeyError`` when asking ``.loc`` for a single missing label is now shorter and more clear (:issue:`21557`) +- :class:`PeriodIndex` now emits a ``KeyError`` when a malformed string is looked up, which is consistent with the behavior of :class:`DateTimeIndex` (:issue:`22803`) - When ``.ix`` is asked for a missing integer label in a :class:`MultiIndex` with a first level of integer type, it now raises a ``KeyError``, consistently with the case of a flat :class:`Int64Index`, rather than falling back to positional indexing (:issue:`21593`) - Bug in :meth:`DatetimeIndex.reindex` when reindexing a tz-naive and tz-aware :class:`DatetimeIndex` (:issue:`8306`) - Bug in :meth:`Series.reindex` when reindexing an empty series with a ``datetime64[ns, tz]`` dtype (:issue:`20869`) diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 92ffaea521d7f..21e84629b4d3b 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -20,7 +20,7 @@ from pandas.core.indexes.datetimelike import ( DatelikeOps, DatetimeIndexOpsMixin, wrap_arithmetic_op ) -from pandas.core.tools.datetimes import parse_time_string +from pandas.core.tools.datetimes import parse_time_string, DateParseError from pandas._libs import tslib, index as libindex from pandas._libs.tslibs.period import (Period, IncompatibleFrequency, @@ -580,7 +580,10 @@ def searchsorted(self, value, side='left', sorter=None): raise IncompatibleFrequency(msg) value = value.ordinal elif isinstance(value, compat.string_types): - value = Period(value, freq=self.freq).ordinal + try: + value = Period(value, freq=self.freq).ordinal + except DateParseError: + raise KeyError("Cannot interpret '{}' as period".format(value)) return self._ndarray_values.searchsorted(value, side=side, sorter=sorter) @@ -711,6 +714,9 @@ def get_loc(self, key, method=None, tolerance=None): key = asdt except TypeError: pass + except DateParseError: + # A string with invalid format + raise KeyError("Cannot interpret '{}' as period".format(key)) try: key = Period(key, freq=self.freq) diff --git a/pandas/tests/indexes/period/test_indexing.py b/pandas/tests/indexes/period/test_indexing.py index fafba144bb148..880e37c59c9c4 100644 --- a/pandas/tests/indexes/period/test_indexing.py +++ b/pandas/tests/indexes/period/test_indexing.py @@ -3,7 +3,6 @@ import numpy as np import pytest -from pandas._libs import tslibs from pandas._libs.tslibs import period as libperiod from pandas.compat import lrange @@ -363,7 +362,9 @@ def test_get_loc(self): assert idx0.get_loc(p2) == expected_idx1_p2 assert idx0.get_loc(str(p2)) == expected_idx1_p2 - pytest.raises(tslibs.parsing.DateParseError, idx0.get_loc, 'foo') + tm.assert_raises_regex(KeyError, + "Cannot interpret 'foo' as period", + idx0.get_loc, 'foo') pytest.raises(KeyError, idx0.get_loc, 1.1) pytest.raises(TypeError, idx0.get_loc, idx0) @@ -378,7 +379,9 @@ def test_get_loc(self): assert idx1.get_loc(p2) == expected_idx1_p2 assert idx1.get_loc(str(p2)) == expected_idx1_p2 - pytest.raises(tslibs.parsing.DateParseError, idx1.get_loc, 'foo') + tm.assert_raises_regex(KeyError, + "Cannot interpret 'foo' as period", + idx1.get_loc, 'foo') pytest.raises(KeyError, idx1.get_loc, 1.1) pytest.raises(TypeError, idx1.get_loc, idx1)