From cbbaf24e7ee6df4865e5b20fb7f180aa7e49732d Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 27 Nov 2019 19:40:58 -0800 Subject: [PATCH 1/4] DEPR: Remove errors argument in tz_localize --- doc/source/whatsnew/v1.0.0.rst | 1 + pandas/_libs/tslibs/nattype.pyx | 12 -------- pandas/_libs/tslibs/timestamps.pyx | 28 +---------------- pandas/core/arrays/datetimes.py | 30 +------------------ .../tests/indexes/datetimes/test_timezones.py | 22 ++------------ .../tests/scalar/timestamp/test_timezones.py | 28 ++++------------- pandas/tests/series/test_timezones.py | 15 ---------- 7 files changed, 11 insertions(+), 125 deletions(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 8a9b9db140409..2f23e02831986 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -456,6 +456,7 @@ or ``matplotlib.Axes.plot``. See :ref:`plotting.formatters` for more. - Changed the default value for the `raw` argument in :func:`Series.rolling().apply() `, :func:`DataFrame.rolling().apply() `, - :func:`Series.expanding().apply() `, and :func:`DataFrame.expanding().apply() ` to ``False`` (:issue:`20584`) - Removed previously deprecated :attr:`Timestamp.weekday_name`, :attr:`DatetimeIndex.weekday_name`, and :attr:`Series.dt.weekday_name` (:issue:`18164`) +- Removed previously deprecated ``error`` argument in :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` (:issue:`22644`) - .. _whatsnew_1000.performance: diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 966f72dcd7889..76a694c64e1fb 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -720,18 +720,6 @@ default 'raise' nonexistent times. .. versionadded:: 0.24.0 - errors : 'raise', 'coerce', default None - Determine how errors should be handled. - - The behavior is as follows: - - * 'raise' will raise a NonExistentTimeError if a timestamp is not - valid in the specified timezone (e.g. due to a transition from - or to DST time). Use ``nonexistent='raise'`` instead. - * 'coerce' will return NaT if the timestamp can not be converted - into the specified timezone. Use ``nonexistent='NaT'`` instead. - - .. deprecated:: 0.24.0 Returns ------- diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 08e504ada789e..e7dc911ff0bae 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -753,8 +753,7 @@ timedelta}, default 'raise' # GH#21336, GH#21365 return Timedelta(nanoseconds=1) - def tz_localize(self, tz, ambiguous='raise', nonexistent='raise', - errors=None): + def tz_localize(self, tz, ambiguous='raise', nonexistent='raise'): """ Convert naive Timestamp to local time zone, or remove timezone from tz-aware Timestamp. @@ -797,18 +796,6 @@ default 'raise' nonexistent times. .. versionadded:: 0.24.0 - errors : 'raise', 'coerce', default None - Determine how errors should be handled. - - The behavior is as follows: - - * 'raise' will raise a NonExistentTimeError if a timestamp is not - valid in the specified timezone (e.g. due to a transition from - or to DST time). Use ``nonexistent='raise'`` instead. - * 'coerce' will return NaT if the timestamp can not be converted - into the specified timezone. Use ``nonexistent='NaT'`` instead. - - .. deprecated:: 0.24.0 Returns ------- @@ -822,19 +809,6 @@ default 'raise' if ambiguous == 'infer': raise ValueError('Cannot infer offset with only one time.') - if errors is not None: - warnings.warn("The errors argument is deprecated and will be " - "removed in a future release. Use " - "nonexistent='NaT' or nonexistent='raise' " - "instead.", FutureWarning) - if errors == 'coerce': - nonexistent = 'NaT' - elif errors == 'raise': - nonexistent = 'raise' - else: - raise ValueError("The errors argument must be either 'coerce' " - "or 'raise'.") - nonexistent_options = ('raise', 'NaT', 'shift_forward', 'shift_backward') if nonexistent not in nonexistent_options and not isinstance( diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 07cbaa8cd1eb6..47f236c19ffe7 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -955,7 +955,7 @@ def tz_convert(self, tz): dtype = tz_to_dtype(tz) return self._simple_new(self.asi8, dtype=dtype, freq=self.freq) - def tz_localize(self, tz, ambiguous="raise", nonexistent="raise", errors=None): + def tz_localize(self, tz, ambiguous="raise", nonexistent="raise"): """ Localize tz-naive Datetime Array/Index to tz-aware Datetime Array/Index. @@ -1004,17 +1004,6 @@ def tz_localize(self, tz, ambiguous="raise", nonexistent="raise", errors=None): .. versionadded:: 0.24.0 - errors : {'raise', 'coerce'}, default None - The method to handle errors: - - - 'raise' will raise a NonExistentTimeError if a timestamp is not - valid in the specified time zone (e.g. due to a transition from - or to DST time). Use ``nonexistent='raise'`` instead. - - 'coerce' will return NaT if the timestamp can not be converted - to the specified time zone. Use ``nonexistent='NaT'`` instead. - - .. deprecated:: 0.24.0 - Returns ------- Same type as self @@ -1105,23 +1094,6 @@ def tz_localize(self, tz, ambiguous="raise", nonexistent="raise", errors=None): 1 2015-03-29 03:30:00+02:00 dtype: datetime64[ns, 'Europe/Warsaw'] """ - if errors is not None: - warnings.warn( - "The errors argument is deprecated and will be " - "removed in a future release. Use " - "nonexistent='NaT' or nonexistent='raise' " - "instead.", - FutureWarning, - ) - if errors == "coerce": - nonexistent = "NaT" - elif errors == "raise": - nonexistent = "raise" - else: - raise ValueError( - "The errors argument must be either 'coerce' or 'raise'." - ) - nonexistent_options = ("raise", "NaT", "shift_forward", "shift_backward") if nonexistent not in nonexistent_options and not isinstance( nonexistent, timedelta diff --git a/pandas/tests/indexes/datetimes/test_timezones.py b/pandas/tests/indexes/datetimes/test_timezones.py index 059dbb00019d8..39a8108cf1c85 100644 --- a/pandas/tests/indexes/datetimes/test_timezones.py +++ b/pandas/tests/indexes/datetimes/test_timezones.py @@ -323,13 +323,9 @@ def test_dti_tz_localize_nonexistent_raise_coerce(self): index.tz_localize(tz=tz) with pytest.raises(pytz.NonExistentTimeError): - with tm.assert_produces_warning(FutureWarning): - index.tz_localize(tz=tz, errors="raise") + index.tz_localize(tz=tz, nonexistent="raise") - with tm.assert_produces_warning( - FutureWarning, clear=FutureWarning, check_stacklevel=False - ): - result = index.tz_localize(tz=tz, errors="coerce") + result = index.tz_localize(tz=tz, nonexistent="coerce") test_times = ["2015-03-08 01:00-05:00", "NaT", "2015-03-08 03:00-04:00"] dti = to_datetime(test_times, utc=True) expected = dti.tz_convert("US/Eastern") @@ -704,20 +700,6 @@ def test_dti_tz_localize_nonexistent_shift_invalid(self, offset, tz_type): with pytest.raises(ValueError, match=msg): dti.tz_localize(tz, nonexistent=timedelta(seconds=offset)) - @pytest.mark.filterwarnings("ignore::FutureWarning") - def test_dti_tz_localize_errors_deprecation(self): - # GH 22644 - tz = "Europe/Warsaw" - n = 60 - dti = date_range(start="2015-03-29 02:00:00", periods=n, freq="min") - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - with pytest.raises(ValueError): - dti.tz_localize(tz, errors="foo") - # make sure errors='coerce' gets mapped correctly to nonexistent - result = dti.tz_localize(tz, errors="coerce") - expected = dti.tz_localize(tz, nonexistent="NaT") - tm.assert_index_equal(result, expected) - # ------------------------------------------------------------- # DatetimeIndex.normalize diff --git a/pandas/tests/scalar/timestamp/test_timezones.py b/pandas/tests/scalar/timestamp/test_timezones.py index 250f48b7e711b..6f9d7f763bcba 100644 --- a/pandas/tests/scalar/timestamp/test_timezones.py +++ b/pandas/tests/scalar/timestamp/test_timezones.py @@ -80,7 +80,6 @@ def test_tz_localize_ambiguous(self): ("2015-03-29 02:30", "Europe/Belgrade"), ], ) - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_tz_localize_nonexistent(self, stamp, tz): # GH#13057 ts = Timestamp(stamp) @@ -88,36 +87,21 @@ def test_tz_localize_nonexistent(self, stamp, tz): ts.tz_localize(tz) # GH 22644 with pytest.raises(NonExistentTimeError): - with tm.assert_produces_warning(FutureWarning): - ts.tz_localize(tz, errors="raise") - with tm.assert_produces_warning(FutureWarning): - assert ts.tz_localize(tz, errors="coerce") is NaT + ts.tz_localize(tz, nonexistent="raise") + assert ts.tz_localize(tz, nonexistent="coerce") is NaT - def test_tz_localize_errors_ambiguous(self): + def test_tz_localize_ambiguous(self): # GH#13057 ts = Timestamp("2015-11-1 01:00") with pytest.raises(AmbiguousTimeError): - with tm.assert_produces_warning(FutureWarning): - ts.tz_localize("US/Pacific", errors="coerce") + ts.tz_localize("US/Pacific", ambiguous="coerce") - @pytest.mark.filterwarnings("ignore::FutureWarning") - def test_tz_localize_errors_invalid_arg(self): + def test_tz_localize_nonexistent_invalid_arg(self): # GH 22644 tz = "Europe/Warsaw" ts = Timestamp("2015-03-29 02:00:00") with pytest.raises(ValueError): - with tm.assert_produces_warning(FutureWarning): - ts.tz_localize(tz, errors="foo") - - def test_tz_localize_errors_coerce(self): - # GH 22644 - # make sure errors='coerce' gets mapped correctly to nonexistent - tz = "Europe/Warsaw" - ts = Timestamp("2015-03-29 02:00:00") - with tm.assert_produces_warning(FutureWarning): - result = ts.tz_localize(tz, errors="coerce") - expected = ts.tz_localize(tz, nonexistent="NaT") - assert result is expected + ts.tz_localize(tz, nonexistent="foo") @pytest.mark.parametrize( "stamp", diff --git a/pandas/tests/series/test_timezones.py b/pandas/tests/series/test_timezones.py index c16e2864b131f..c03101265f7e7 100644 --- a/pandas/tests/series/test_timezones.py +++ b/pandas/tests/series/test_timezones.py @@ -33,21 +33,6 @@ def test_series_tz_localize(self): with pytest.raises(TypeError, match="Already tz-aware"): ts.tz_localize("US/Eastern") - @pytest.mark.filterwarnings("ignore::FutureWarning") - def test_tz_localize_errors_deprecation(self): - # GH 22644 - tz = "Europe/Warsaw" - n = 60 - rng = date_range(start="2015-03-29 02:00:00", periods=n, freq="min") - ts = Series(rng) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - with pytest.raises(ValueError): - ts.dt.tz_localize(tz, errors="foo") - # make sure errors='coerce' gets mapped correctly to nonexistent - result = ts.dt.tz_localize(tz, errors="coerce") - expected = ts.dt.tz_localize(tz, nonexistent="NaT") - tm.assert_series_equal(result, expected) - def test_series_tz_localize_ambiguous_bool(self): # make sure that we are correctly accepting bool values as ambiguous From 3592e0dd2fccf53268f31e5e8b67d1838c18a717 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 27 Nov 2019 19:43:27 -0800 Subject: [PATCH 2/4] Fix test and whatsnew note --- doc/source/whatsnew/v1.0.0.rst | 2 +- pandas/tests/scalar/timestamp/test_timezones.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 2f23e02831986..e67d2d71315d4 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -456,7 +456,7 @@ or ``matplotlib.Axes.plot``. See :ref:`plotting.formatters` for more. - Changed the default value for the `raw` argument in :func:`Series.rolling().apply() `, :func:`DataFrame.rolling().apply() `, - :func:`Series.expanding().apply() `, and :func:`DataFrame.expanding().apply() ` to ``False`` (:issue:`20584`) - Removed previously deprecated :attr:`Timestamp.weekday_name`, :attr:`DatetimeIndex.weekday_name`, and :attr:`Series.dt.weekday_name` (:issue:`18164`) -- Removed previously deprecated ``error`` argument in :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` (:issue:`22644`) +- Removed previously deprecated ``errors`` argument in :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` (:issue:`22644`) - .. _whatsnew_1000.performance: diff --git a/pandas/tests/scalar/timestamp/test_timezones.py b/pandas/tests/scalar/timestamp/test_timezones.py index 6f9d7f763bcba..9791b4ee6682e 100644 --- a/pandas/tests/scalar/timestamp/test_timezones.py +++ b/pandas/tests/scalar/timestamp/test_timezones.py @@ -94,7 +94,7 @@ def test_tz_localize_ambiguous(self): # GH#13057 ts = Timestamp("2015-11-1 01:00") with pytest.raises(AmbiguousTimeError): - ts.tz_localize("US/Pacific", ambiguous="coerce") + ts.tz_localize("US/Pacific", ambiguous="raise") def test_tz_localize_nonexistent_invalid_arg(self): # GH 22644 From 602d6baa630aa6b84366ce934e967be799c4dcc2 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 27 Nov 2019 21:44:26 -0800 Subject: [PATCH 3/4] Fix tests --- pandas/tests/indexes/datetimes/test_timezones.py | 2 +- pandas/tests/scalar/timestamp/test_timezones.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_timezones.py b/pandas/tests/indexes/datetimes/test_timezones.py index 39a8108cf1c85..3f942f9b79428 100644 --- a/pandas/tests/indexes/datetimes/test_timezones.py +++ b/pandas/tests/indexes/datetimes/test_timezones.py @@ -325,7 +325,7 @@ def test_dti_tz_localize_nonexistent_raise_coerce(self): with pytest.raises(pytz.NonExistentTimeError): index.tz_localize(tz=tz, nonexistent="raise") - result = index.tz_localize(tz=tz, nonexistent="coerce") + result = index.tz_localize(tz=tz, nonexistent="NaT") test_times = ["2015-03-08 01:00-05:00", "NaT", "2015-03-08 03:00-04:00"] dti = to_datetime(test_times, utc=True) expected = dti.tz_convert("US/Eastern") diff --git a/pandas/tests/scalar/timestamp/test_timezones.py b/pandas/tests/scalar/timestamp/test_timezones.py index 9791b4ee6682e..2ff694c92d3d3 100644 --- a/pandas/tests/scalar/timestamp/test_timezones.py +++ b/pandas/tests/scalar/timestamp/test_timezones.py @@ -88,7 +88,7 @@ def test_tz_localize_nonexistent(self, stamp, tz): # GH 22644 with pytest.raises(NonExistentTimeError): ts.tz_localize(tz, nonexistent="raise") - assert ts.tz_localize(tz, nonexistent="coerce") is NaT + assert ts.tz_localize(tz, nonexistent="NaT") is NaT def test_tz_localize_ambiguous(self): # GH#13057 From aa5c7e3b38d08bfa3f8aed71114d529120e33308 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Thu, 28 Nov 2019 11:55:50 -0800 Subject: [PATCH 4/4] Lint --- pandas/tests/scalar/timestamp/test_timezones.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/tests/scalar/timestamp/test_timezones.py b/pandas/tests/scalar/timestamp/test_timezones.py index 2ff694c92d3d3..6537f6ccd8432 100644 --- a/pandas/tests/scalar/timestamp/test_timezones.py +++ b/pandas/tests/scalar/timestamp/test_timezones.py @@ -14,7 +14,6 @@ import pandas.util._test_decorators as td from pandas import NaT, Timestamp -import pandas.util.testing as tm class TestTimestampTZOperations: @@ -90,7 +89,7 @@ def test_tz_localize_nonexistent(self, stamp, tz): ts.tz_localize(tz, nonexistent="raise") assert ts.tz_localize(tz, nonexistent="NaT") is NaT - def test_tz_localize_ambiguous(self): + def test_tz_localize_ambiguous_raise(self): # GH#13057 ts = Timestamp("2015-11-1 01:00") with pytest.raises(AmbiguousTimeError):