From de4fb4dba010002b78b139d458d67926dbdb4e08 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 3 Oct 2020 18:55:53 +0200 Subject: [PATCH 01/22] Throw warning when M,Y,m or y is used in an arg for pd.to_timedelta --- pandas/core/tools/timedeltas.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 372eac29bad9e..5029d9867daa6 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -1,6 +1,7 @@ """ timedelta support tools """ +import warnings import numpy as np @@ -118,8 +119,18 @@ def to_timedelta(arg, unit=None, errors="raise"): "arg must be a string, timedelta, list, tuple, 1-d array, or Series" ) - if isinstance(arg, str) and unit is not None: - raise ValueError("unit must not be specified if the input is/contains a str") + if isinstance(arg, str): + if unit is not None: + raise ValueError( + "unit must not be specified if the input is/contains a str" + ) + elif arg.upper().endswith(" M") or arg.upper().endswith(" Y"): + warnings.warn( + "'M', 'Y', 'm' and 'y' do not represent unambiguous timedelta values" + " durations. and will removed in a future version", + FutureWarning, + stacklevel=2, + ) # ...so it must be a scalar value. Return scalar. return _coerce_scalar_to_timedelta_type(arg, unit=unit, errors=errors) From 61ec5b6625b5bd1a1aa193251f4d86fd0af2e29c Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 3 Oct 2020 19:02:27 +0200 Subject: [PATCH 02/22] Update docstring by removing old logic and adding depr notice --- pandas/core/tools/timedeltas.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 5029d9867daa6..0e93e08fa6fbf 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -26,10 +26,13 @@ def to_timedelta(arg, unit=None, errors="raise"): Parameters ---------- arg : str, timedelta, list-like or Series - The data to be converted to timedelta. The character M by itself, - e.g. '1M', is treated as minute, not month. The characters Y and y - are treated as the mean length of the Gregorian calendar year - - 365.2425 days or 365 days 5 hours 49 minutes 12 seconds. + The data to be converted to timedelta. + + .. deprecated:: 1.2 + Strings denoting units with 'M', 'Y', 'm' and 'y' do not represent + unambiguous timedelta values durations and will removed in a future + version + unit : str, optional Denotes the unit of the arg for numeric `arg`. Defaults to ``"ns"``. @@ -126,8 +129,8 @@ def to_timedelta(arg, unit=None, errors="raise"): ) elif arg.upper().endswith(" M") or arg.upper().endswith(" Y"): warnings.warn( - "'M', 'Y', 'm' and 'y' do not represent unambiguous timedelta values" - " durations. and will removed in a future version", + "Denoting units with 'M', 'Y', 'm' and 'y' do not represent unambiguous" + " timedelta values durations and will removed in a future version", FutureWarning, stacklevel=2, ) From abb613e15dbe6cb0fbc140a32395d85328271f18 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 3 Oct 2020 19:28:43 +0200 Subject: [PATCH 03/22] Add whatsnew entry --- doc/source/whatsnew/v1.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index bd3112403b31b..3a2423c2b9465 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -293,6 +293,7 @@ Deprecations - :meth:`Rolling.count` with ``min_periods=None`` will default to the size of the window in a future version (:issue:`31302`) - Deprecated slice-indexing on timezone-aware :class:`DatetimeIndex` with naive ``datetime`` objects, to match scalar indexing behavior (:issue:`36148`) - :meth:`Index.ravel` returning a ``np.ndarray`` is deprecated, in the future this will return a view on the same index (:issue:`19956`) +- Deprecate use of strings denoting units with 'M', 'Y', 'm' and 'y' in :func:`~pandas.to_timedelta` (:issue:`36666`) .. --------------------------------------------------------------------------- From 4ccf43d6c227967169bf0d54841d0b1ce458f39f Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 3 Oct 2020 19:33:47 +0200 Subject: [PATCH 04/22] Update wording in docs --- doc/source/whatsnew/v1.2.0.rst | 2 +- pandas/core/tools/timedeltas.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 3a2423c2b9465..f66c83ca79b82 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -293,7 +293,7 @@ Deprecations - :meth:`Rolling.count` with ``min_periods=None`` will default to the size of the window in a future version (:issue:`31302`) - Deprecated slice-indexing on timezone-aware :class:`DatetimeIndex` with naive ``datetime`` objects, to match scalar indexing behavior (:issue:`36148`) - :meth:`Index.ravel` returning a ``np.ndarray`` is deprecated, in the future this will return a view on the same index (:issue:`19956`) -- Deprecate use of strings denoting units with 'M', 'Y', 'm' and 'y' in :func:`~pandas.to_timedelta` (:issue:`36666`) +- Deprecate use of strings denoting units with 'M', 'Y', 'm' or 'y' in :func:`~pandas.to_timedelta` (:issue:`36666`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 0e93e08fa6fbf..ca42830ecaeef 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -29,7 +29,7 @@ def to_timedelta(arg, unit=None, errors="raise"): The data to be converted to timedelta. .. deprecated:: 1.2 - Strings denoting units with 'M', 'Y', 'm' and 'y' do not represent + Strings denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous timedelta values durations and will removed in a future version @@ -129,7 +129,7 @@ def to_timedelta(arg, unit=None, errors="raise"): ) elif arg.upper().endswith(" M") or arg.upper().endswith(" Y"): warnings.warn( - "Denoting units with 'M', 'Y', 'm' and 'y' do not represent unambiguous" + "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous" " timedelta values durations and will removed in a future version", FutureWarning, stacklevel=2, From 271f2fc89ced7eb3e32c7b74d571e7922629abc2 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 3 Oct 2020 20:02:11 +0200 Subject: [PATCH 05/22] Place space at the end of string instead of at the beginning of next line --- pandas/core/tools/timedeltas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index ca42830ecaeef..606eb9208c51c 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -129,8 +129,8 @@ def to_timedelta(arg, unit=None, errors="raise"): ) elif arg.upper().endswith(" M") or arg.upper().endswith(" Y"): warnings.warn( - "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous" - " timedelta values durations and will removed in a future version", + "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " + "timedelta values durations and will removed in a future version", FutureWarning, stacklevel=2, ) From 7b11a92d4cc9e968f2b6da603635fad0a1bb8364 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 4 Oct 2020 13:21:34 +0200 Subject: [PATCH 06/22] Also catch month and year timedelta variations without a space --- pandas/core/tools/timedeltas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 606eb9208c51c..dd5cf574c7b5c 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -127,7 +127,7 @@ def to_timedelta(arg, unit=None, errors="raise"): raise ValueError( "unit must not be specified if the input is/contains a str" ) - elif arg.upper().endswith(" M") or arg.upper().endswith(" Y"): + elif arg.upper().endswith("M") or arg.upper().endswith("Y"): warnings.warn( "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " "timedelta values durations and will removed in a future version", From b39eadf61374273cdc418fcb4929a777d8eb1cfb Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 4 Oct 2020 13:35:36 +0200 Subject: [PATCH 07/22] Add test for depr behavior --- pandas/tests/tools/test_to_timedelta.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index f68d83f7f4d58..7780d46a4e1b6 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -121,6 +121,23 @@ def test_to_timedelta_invalid(self): invalid_data, to_timedelta(invalid_data, errors="ignore") ) + @pytest.mark.parametrize( + "val", + [ + "1M", + "1 M", + "1Y", + "1 Y", + "1m", + "1 m", + "1y", + "1 y", + ], + ) + def test_unambiguous_timedelta_values(self, val): + with tm.assert_produces_warning(FutureWarning): + to_timedelta(val) + def test_to_timedelta_via_apply(self): # GH 5458 expected = Series([np.timedelta64(1, "s")]) From f56796a131e922bdd5005a190651314744b242e9 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 4 Oct 2020 16:03:39 +0200 Subject: [PATCH 08/22] Catch deprecated patterns with a regex to prevent false positives and update tests --- pandas/core/tools/timedeltas.py | 3 ++- .../tests/scalar/timedelta/test_timedelta.py | 4 +++- pandas/tests/tools/test_to_timedelta.py | 24 ++++++++++--------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index dd5cf574c7b5c..74b8b63aa919d 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -1,6 +1,7 @@ """ timedelta support tools """ +import re import warnings import numpy as np @@ -127,7 +128,7 @@ def to_timedelta(arg, unit=None, errors="raise"): raise ValueError( "unit must not be specified if the input is/contains a str" ) - elif arg.upper().endswith("M") or arg.upper().endswith("Y"): + elif re.search(r"^\d+\s?[M|Y|m|y]$", arg): warnings.warn( "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " "timedelta values durations and will removed in a future version", diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index a01921bd6c4c2..725c1206c9b31 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -258,7 +258,9 @@ def test_unit_parser(self, units, np_unit, wrapper): if unit == "M": expected = Timedelta(np.timedelta64(2, "m").astype("timedelta64[ns]")) - result = to_timedelta(f"2{unit}") + warning = None if unit != "m" else FutureWarning + with tm.assert_produces_warning(warning): + result = to_timedelta(f"2{unit}") assert result == expected result = Timedelta(f"2{unit}") assert result == expected diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index 7780d46a4e1b6..0cad173cfc52b 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -122,20 +122,22 @@ def test_to_timedelta_invalid(self): ) @pytest.mark.parametrize( - "val", + "val, warning", [ - "1M", - "1 M", - "1Y", - "1 Y", - "1m", - "1 m", - "1y", - "1 y", + ("1M", FutureWarning), + ("1 M", FutureWarning), + ("1Y", FutureWarning), + ("1 Y", FutureWarning), + ("1m", FutureWarning), + ("1 m", FutureWarning), + ("1y", FutureWarning), + ("1 y", FutureWarning), + ("1 day", None), + ("2day", None), ], ) - def test_unambiguous_timedelta_values(self, val): - with tm.assert_produces_warning(FutureWarning): + def test_unambiguous_timedelta_values(self, val, warning): + with tm.assert_produces_warning(warning): to_timedelta(val) def test_to_timedelta_via_apply(self): From ad38ad349ea4fd500118782a6af2f99bfbb4e2d8 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Mon, 12 Oct 2020 09:03:11 +0200 Subject: [PATCH 09/22] Add description to unittest --- pandas/tests/tools/test_to_timedelta.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index 0cad173cfc52b..36e4498924e36 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -137,6 +137,8 @@ def test_to_timedelta_invalid(self): ], ) def test_unambiguous_timedelta_values(self, val, warning): + # GH36666 Deprecate use of strings denoting units with 'M', 'Y', 'm' or 'y' + # in pd.to_timedelta with tm.assert_produces_warning(warning): to_timedelta(val) From bc0306577e34b2da790926577e6ad0ac504c4550 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Tue, 13 Oct 2020 23:47:26 +0200 Subject: [PATCH 10/22] Also find appearences of unambiguous timedelta values in containers --- pandas/_libs/tslibs/timedeltas.pyx | 11 +++++++++++ pandas/core/tools/timedeltas.py | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index ee32ed53a908b..68960e8e4202f 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,4 +1,5 @@ import collections +import re import cython @@ -1467,6 +1468,16 @@ cdef _broadcast_floordiv_td64( return res +def check_unambiguous_timedelta_values(object[:] values): + cdef: + Py_ssize_t i, n = len(values) + + for i in range(n): + if re.search(r"^\d+\s?[M|Y|m|y]$", str(values[i])): + return True + return False + + # resolution in ns Timedelta.min = Timedelta(np.iinfo(np.int64).min + 1) Timedelta.max = Timedelta(np.iinfo(np.int64).max) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 74b8b63aa919d..a864932fa158e 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -7,7 +7,11 @@ import numpy as np from pandas._libs.tslibs import NaT -from pandas._libs.tslibs.timedeltas import Timedelta, parse_timedelta_unit +from pandas._libs.tslibs.timedeltas import ( + Timedelta, + check_unambiguous_timedelta_values, + parse_timedelta_unit, +) from pandas.core.dtypes.common import is_list_like from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries @@ -106,6 +110,16 @@ def to_timedelta(arg, unit=None, errors="raise"): "represent unambiguous timedelta values durations." ) + if isinstance(arg, (list, tuple, ABCSeries, ABCIndexClass, np.ndarray)): + arr = np.array(arg, dtype="object", ndmin=1) + if arr.ndim == 1 and check_unambiguous_timedelta_values(arr): + warnings.warn( + "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " + "timedelta values durations and will removed in a future version", + FutureWarning, + stacklevel=2, + ) + if arg is None: return arg elif isinstance(arg, ABCSeries): From d491cce6e74f76dd33bbbb012042eea2d057f0b4 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Thu, 15 Oct 2020 22:32:27 +0200 Subject: [PATCH 11/22] Update test_unit_parser in test_timedelta.py --- .../tests/scalar/timedelta/test_timedelta.py | 199 +++++++++--------- 1 file changed, 104 insertions(+), 95 deletions(-) diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 725c1206c9b31..87bb1525cabe3 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -160,110 +160,119 @@ def test_nat_converters(self): assert result.astype("int64") == iNaT @pytest.mark.parametrize( - "units, np_unit", - [ - (["W", "w"], "W"), - (["D", "d", "days", "day", "Days", "Day"], "D"), - ( - ["m", "minute", "min", "minutes", "t", "Minute", "Min", "Minutes", "T"], + "unit, np_unit, warning", + [(value, "W", False) for value in ["W", "w"]] + + [(value, "D", False) for value in ["D", "d", "days", "day", "Days", "Day"]] + + [ + (value, "m", FutureWarning if value == "m" else False) + for value in [ "m", - ), - (["s", "seconds", "sec", "second", "S", "Seconds", "Sec", "Second"], "s"), - ( - [ - "ms", - "milliseconds", - "millisecond", - "milli", - "millis", - "l", - "MS", - "Milliseconds", - "Millisecond", - "Milli", - "Millis", - "L", - ], + "minute", + "min", + "minutes", + "t", + "Minute", + "Min", + "Minutes", + "T", + ] + ] + + [ + (value, "s", False) + for value in [ + "s", + "seconds", + "sec", + "second", + "S", + "Seconds", + "Sec", + "Second", + ] + ] + + [ + (value, "ms", False) + for value in [ "ms", - ), - ( - [ - "us", - "microseconds", - "microsecond", - "micro", - "micros", - "u", - "US", - "Microseconds", - "Microsecond", - "Micro", - "Micros", - "U", - ], + "milliseconds", + "millisecond", + "milli", + "millis", + "l", + "MS", + "Milliseconds", + "Millisecond", + "Milli", + "Millis", + "L", + ] + ] + + [ + (value, "us", False) + for value in [ "us", - ), - ( - [ - "ns", - "nanoseconds", - "nanosecond", - "nano", - "nanos", - "n", - "NS", - "Nanoseconds", - "Nanosecond", - "Nano", - "Nanos", - "N", - ], + "microseconds", + "microsecond", + "micro", + "micros", + "u", + "US", + "Microseconds", + "Microsecond", + "Micro", + "Micros", + "U", + ] + ] + + [ + (value, "ns", False) + for value in [ "ns", - ), + "nanoseconds", + "nanosecond", + "nano", + "nanos", + "n", + "NS", + "Nanoseconds", + "Nanosecond", + "Nano", + "Nanos", + "N", + ] ], ) @pytest.mark.parametrize("wrapper", [np.array, list, pd.Index]) - def test_unit_parser(self, units, np_unit, wrapper): + def test_unit_parser(self, unit, np_unit, wrapper, warning): # validate all units, GH 6855, GH 21762 - for unit in units: - # array-likes - expected = TimedeltaIndex( - [np.timedelta64(i, np_unit) for i in np.arange(5).tolist()] - ) - result = to_timedelta(wrapper(range(5)), unit=unit) - tm.assert_index_equal(result, expected) - result = TimedeltaIndex(wrapper(range(5)), unit=unit) - tm.assert_index_equal(result, expected) - - if unit == "M": - # M is treated as minutes in string repr - expected = TimedeltaIndex( - [np.timedelta64(i, "m") for i in np.arange(5).tolist()] - ) - - str_repr = [f"{x}{unit}" for x in np.arange(5)] + # array-likes + expected = TimedeltaIndex( + [np.timedelta64(i, np_unit) for i in np.arange(5).tolist()] + ) + result = to_timedelta(wrapper(range(5)), unit=unit) + tm.assert_index_equal(result, expected) + result = TimedeltaIndex(wrapper(range(5)), unit=unit) + tm.assert_index_equal(result, expected) + + str_repr = [f"{x}{unit}" for x in np.arange(5)] + with tm.assert_produces_warning(warning): result = to_timedelta(wrapper(str_repr)) - tm.assert_index_equal(result, expected) - result = TimedeltaIndex(wrapper(str_repr)) - tm.assert_index_equal(result, expected) - - # scalar - expected = Timedelta(np.timedelta64(2, np_unit).astype("timedelta64[ns]")) - - result = to_timedelta(2, unit=unit) - assert result == expected - result = Timedelta(2, unit=unit) - assert result == expected - - if unit == "M": - expected = Timedelta(np.timedelta64(2, "m").astype("timedelta64[ns]")) - - warning = None if unit != "m" else FutureWarning - with tm.assert_produces_warning(warning): - result = to_timedelta(f"2{unit}") - assert result == expected - result = Timedelta(f"2{unit}") - assert result == expected + tm.assert_index_equal(result, expected) + result = TimedeltaIndex(wrapper(str_repr)) + tm.assert_index_equal(result, expected) + + # scalar + expected = Timedelta(np.timedelta64(2, np_unit).astype("timedelta64[ns]")) + result = to_timedelta(2, unit=unit) + assert result == expected + result = Timedelta(2, unit=unit) + assert result == expected + + with tm.assert_produces_warning(warning): + result = to_timedelta(f"2{unit}") + assert result == expected + result = Timedelta(f"2{unit}") + assert result == expected @pytest.mark.parametrize("unit", ["Y", "y", "M"]) def test_unit_m_y_raises(self, unit): From 76e6602b886050ee1237e42e5423b6e4594886b2 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 18 Oct 2020 15:06:56 +0200 Subject: [PATCH 12/22] Move warnings code to timedeltas.pyx and update tests --- pandas/_libs/tslibs/timedeltas.pyx | 19 ++++++----- pandas/core/tools/timedeltas.py | 32 ++----------------- .../tests/scalar/timedelta/test_timedelta.py | 11 ++++--- pandas/tests/tools/test_to_timedelta.py | 2 +- 4 files changed, 20 insertions(+), 44 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 68960e8e4202f..a196a0d491d01 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,5 +1,6 @@ import collections import re +import warnings import cython @@ -298,6 +299,14 @@ cdef inline int64_t parse_timedelta_string(str ts) except? -1: if len(ts) == 0 or ts in nat_strings: return NPY_NAT + if re.search(r"^\d+\s?[M|Y|m|y]$", ts): + warnings.warn( + "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " + "timedelta values durations and will be removed in a future version", + FutureWarning, + stacklevel=2, + ) + for c in ts: # skip whitespace / commas @@ -1468,16 +1477,6 @@ cdef _broadcast_floordiv_td64( return res -def check_unambiguous_timedelta_values(object[:] values): - cdef: - Py_ssize_t i, n = len(values) - - for i in range(n): - if re.search(r"^\d+\s?[M|Y|m|y]$", str(values[i])): - return True - return False - - # resolution in ns Timedelta.min = Timedelta(np.iinfo(np.int64).min + 1) Timedelta.max = Timedelta(np.iinfo(np.int64).max) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index a864932fa158e..585e19cb11366 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -1,17 +1,11 @@ """ timedelta support tools """ -import re -import warnings import numpy as np from pandas._libs.tslibs import NaT -from pandas._libs.tslibs.timedeltas import ( - Timedelta, - check_unambiguous_timedelta_values, - parse_timedelta_unit, -) +from pandas._libs.tslibs.timedeltas import Timedelta, parse_timedelta_unit from pandas.core.dtypes.common import is_list_like from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries @@ -110,16 +104,6 @@ def to_timedelta(arg, unit=None, errors="raise"): "represent unambiguous timedelta values durations." ) - if isinstance(arg, (list, tuple, ABCSeries, ABCIndexClass, np.ndarray)): - arr = np.array(arg, dtype="object", ndmin=1) - if arr.ndim == 1 and check_unambiguous_timedelta_values(arr): - warnings.warn( - "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " - "timedelta values durations and will removed in a future version", - FutureWarning, - stacklevel=2, - ) - if arg is None: return arg elif isinstance(arg, ABCSeries): @@ -137,18 +121,8 @@ def to_timedelta(arg, unit=None, errors="raise"): "arg must be a string, timedelta, list, tuple, 1-d array, or Series" ) - if isinstance(arg, str): - if unit is not None: - raise ValueError( - "unit must not be specified if the input is/contains a str" - ) - elif re.search(r"^\d+\s?[M|Y|m|y]$", arg): - warnings.warn( - "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " - "timedelta values durations and will removed in a future version", - FutureWarning, - stacklevel=2, - ) + if isinstance(arg, str) and unit is not None: + raise ValueError("unit must not be specified if the input is/contains a str") # ...so it must be a scalar value. Return scalar. return _coerce_scalar_to_timedelta_type(arg, unit=unit, errors=errors) diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 87bb1525cabe3..cd1665d29fd8e 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -255,10 +255,12 @@ def test_unit_parser(self, unit, np_unit, wrapper, warning): tm.assert_index_equal(result, expected) str_repr = [f"{x}{unit}" for x in np.arange(5)] - with tm.assert_produces_warning(warning): + with tm.assert_produces_warning(warning, check_stacklevel=False): result = to_timedelta(wrapper(str_repr)) tm.assert_index_equal(result, expected) - result = TimedeltaIndex(wrapper(str_repr)) + with tm.assert_produces_warning(warning, check_stacklevel=False): + result = to_timedelta(wrapper(str_repr)) + tm.assert_index_equal(result, expected) # scalar @@ -268,10 +270,11 @@ def test_unit_parser(self, unit, np_unit, wrapper, warning): result = Timedelta(2, unit=unit) assert result == expected - with tm.assert_produces_warning(warning): + with tm.assert_produces_warning(warning, check_stacklevel=False): result = to_timedelta(f"2{unit}") assert result == expected - result = Timedelta(f"2{unit}") + with tm.assert_produces_warning(warning, check_stacklevel=False): + result = Timedelta(f"2{unit}") assert result == expected @pytest.mark.parametrize("unit", ["Y", "y", "M"]) diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index 36e4498924e36..cbb407f759253 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -139,7 +139,7 @@ def test_to_timedelta_invalid(self): def test_unambiguous_timedelta_values(self, val, warning): # GH36666 Deprecate use of strings denoting units with 'M', 'Y', 'm' or 'y' # in pd.to_timedelta - with tm.assert_produces_warning(warning): + with tm.assert_produces_warning(warning, check_stacklevel=False): to_timedelta(val) def test_to_timedelta_via_apply(self): From cdc582146bc2dc595a3241320d549f67174a1893 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 18 Oct 2020 16:46:33 +0200 Subject: [PATCH 13/22] Update code for failing tests --- doc/source/whatsnew/v0.15.0.rst | 1 + pandas/tests/generic/test_series.py | 2 +- pandas/tests/indexes/interval/test_interval.py | 2 +- pandas/tests/resample/test_datetime_index.py | 6 ++++-- pandas/tests/scalar/timedelta/test_constructors.py | 6 ++++-- pandas/tests/scalar/timedelta/test_timedelta.py | 2 +- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/source/whatsnew/v0.15.0.rst b/doc/source/whatsnew/v0.15.0.rst index 1f054930b3709..f31861562f0a1 100644 --- a/doc/source/whatsnew/v0.15.0.rst +++ b/doc/source/whatsnew/v0.15.0.rst @@ -1030,6 +1030,7 @@ Other: If ``Period`` freq is ``D``, ``H``, ``T``, ``S``, ``L``, ``U``, ``N``, ``Timedelta``-like can be added if the result can have same freq. Otherwise, only the same ``offsets`` can be added. .. ipython:: python + :okwarning: idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') idx diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 07c02330d85ce..56f68082b0f8c 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -174,7 +174,7 @@ def test_shift_always_copy(self, s, shift_size): # GH22397 assert s.shift(shift_size) is not s - @pytest.mark.parametrize("move_by_freq", [pd.Timedelta("1D"), pd.Timedelta("1M")]) + @pytest.mark.parametrize("move_by_freq", [pd.Timedelta("1D"), pd.Timedelta("1min")]) def test_datetime_shift_always_copy(self, move_by_freq): # GH22397 s = pd.Series(range(5), index=pd.date_range("2017", periods=5)) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index 17a1c69858c11..5af1af3027058 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -86,7 +86,7 @@ def test_properties(self, closed): [1, 1, 2, 5, 15, 53, 217, 1014, 5335, 31240, 201608], [-np.inf, -100, -10, 0.5, 1, 1.5, 3.8, 101, 202, np.inf], pd.to_datetime(["20170101", "20170202", "20170303", "20170404"]), - pd.to_timedelta(["1ns", "2ms", "3s", "4M", "5H", "6D"]), + pd.to_timedelta(["1ns", "2ms", "3s", "4min", "5H", "6D"]), ], ) def test_length(self, closed, breaks): diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index 9475dcc6981ff..6a1354c642015 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -752,7 +752,8 @@ def test_resample_origin(): resampled = ts.resample("5min", origin=offset_timestamp).mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", origin="epoch", offset="2m").mean() + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + resampled = ts.resample("5min", origin="epoch", offset="2m").mean() tm.assert_index_equal(resampled.index, exp_rng) # origin of '1999-31-12 12:02:00' should be equivalent for this case @@ -831,7 +832,8 @@ def test_resample_origin_with_tz(): resampled = ts.resample("5min", origin="1999-12-31 12:02:00+03:00").mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", origin="epoch", offset="2m").mean() + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + resampled = ts.resample("5min", origin="epoch", offset="2m").mean() tm.assert_index_equal(resampled.index, exp_rng) with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index 23fb25b838da6..7fd2b95260c93 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -4,6 +4,7 @@ import pytest from pandas import Timedelta, offsets, to_timedelta +import pandas._testing as tm def test_construction(): @@ -40,8 +41,9 @@ def test_construction(): assert Timedelta("1 hr") == timedelta(hours=1) assert Timedelta("1 hours") == timedelta(hours=1) assert Timedelta("-1 hours") == -timedelta(hours=1) - assert Timedelta("1 m") == timedelta(minutes=1) - assert Timedelta("1.5 m") == timedelta(seconds=90) + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + assert Timedelta("1 m") == timedelta(minutes=1) + assert Timedelta("1.5 m") == timedelta(seconds=90) assert Timedelta("1 minute") == timedelta(minutes=1) assert Timedelta("1 minutes") == timedelta(minutes=1) assert Timedelta("1 s") == timedelta(seconds=1) diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index cd1665d29fd8e..70702ed63fa43 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -164,7 +164,7 @@ def test_nat_converters(self): [(value, "W", False) for value in ["W", "w"]] + [(value, "D", False) for value in ["D", "d", "days", "day", "Days", "Day"]] + [ - (value, "m", FutureWarning if value == "m" else False) + (value, "m", FutureWarning if value == "m" else False) # type: ignore[misc] for value in [ "m", "minute", From 02d642baf1866aa1d1c5947626a9bbd04015cd57 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sun, 18 Oct 2020 19:08:37 +0200 Subject: [PATCH 14/22] Remove empty line --- pandas/tests/scalar/timedelta/test_timedelta.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 70702ed63fa43..8dd372aff9b62 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -260,7 +260,6 @@ def test_unit_parser(self, unit, np_unit, wrapper, warning): tm.assert_index_equal(result, expected) with tm.assert_produces_warning(warning, check_stacklevel=False): result = to_timedelta(wrapper(str_repr)) - tm.assert_index_equal(result, expected) # scalar From 89af5bbd8f7c48b41bdb65bd842f5492f4193648 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Mon, 19 Oct 2020 20:40:13 +0200 Subject: [PATCH 15/22] Update depr message --- pandas/_libs/tslibs/timedeltas.pyx | 4 ++-- pandas/core/tools/timedeltas.py | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index c4326edce4548..36ea5883f64d5 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -301,8 +301,8 @@ cdef inline int64_t parse_timedelta_string(str ts) except? -1: if re.search(r"^\d+\s?[M|Y|m|y]$", ts): warnings.warn( - "Denoting units with 'M', 'Y', 'm' or 'y' do not represent unambiguous " - "timedelta values durations and will be removed in a future version", + "Units 'M', 'Y', 'm' and 'y' do not represent unambiguous " + "timedelta values and will be removed in a future version", FutureWarning, stacklevel=2, ) diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 585e19cb11366..387a3ae0ba0eb 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -28,9 +28,8 @@ def to_timedelta(arg, unit=None, errors="raise"): The data to be converted to timedelta. .. deprecated:: 1.2 - Strings denoting units with 'M', 'Y', 'm' or 'y' do not represent - unambiguous timedelta values durations and will removed in a future - version + Strings with units 'M', 'Y', 'm' and 'y' do not represent + unambiguous timedelta values and will be removed in a future version unit : str, optional Denotes the unit of the arg for numeric `arg`. Defaults to ``"ns"``. From 0bc1a89e9659a2b0dba97c21fdbb0d38d783eeb1 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Fri, 23 Oct 2020 00:49:34 +0200 Subject: [PATCH 16/22] Move warning location and update tests --- pandas/_libs/tslibs/timedeltas.pyx | 17 +++++++++-------- pandas/tests/resample/test_datetime_index.py | 3 +-- .../tests/scalar/timedelta/test_constructors.py | 6 ++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 36ea5883f64d5..224c6f3328021 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -299,14 +299,6 @@ cdef inline int64_t parse_timedelta_string(str ts) except? -1: if len(ts) == 0 or ts in nat_strings: return NPY_NAT - if re.search(r"^\d+\s?[M|Y|m|y]$", ts): - warnings.warn( - "Units 'M', 'Y', 'm' and 'y' do not represent unambiguous " - "timedelta values and will be removed in a future version", - FutureWarning, - stacklevel=2, - ) - for c in ts: # skip whitespace / commas @@ -476,6 +468,15 @@ cdef inline timedelta_from_spec(object number, object frac, object unit): try: unit = ''.join(unit) + + if unit in ["M", "Y", "m", "y"]: + warnings.warn( + "Units 'M', 'Y', 'm' and 'y' do not represent unambiguous " + "timedelta values and will be removed in a future version", + FutureWarning, + stacklevel=2, + ) + if unit == 'M': # To parse ISO 8601 string, 'M' should be treated as minute, # not month diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index 6a1354c642015..e4c967b59bc99 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -752,8 +752,7 @@ def test_resample_origin(): resampled = ts.resample("5min", origin=offset_timestamp).mean() tm.assert_index_equal(resampled.index, exp_rng) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - resampled = ts.resample("5min", origin="epoch", offset="2m").mean() + resampled = ts.resample("5min", origin="epoch", offset="2min").mean() tm.assert_index_equal(resampled.index, exp_rng) # origin of '1999-31-12 12:02:00' should be equivalent for this case diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index bd496ff12dc21..bb4743a259d9c 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -4,7 +4,6 @@ import pytest from pandas import Timedelta, offsets, to_timedelta -import pandas._testing as tm def test_construction(): @@ -41,9 +40,8 @@ def test_construction(): assert Timedelta("1 hr") == timedelta(hours=1) assert Timedelta("1 hours") == timedelta(hours=1) assert Timedelta("-1 hours") == -timedelta(hours=1) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - assert Timedelta("1 m") == timedelta(minutes=1) - assert Timedelta("1.5 m") == timedelta(seconds=90) + assert Timedelta("1 min") == timedelta(minutes=1) + assert Timedelta("1.5 min") == timedelta(seconds=90) assert Timedelta("1 minute") == timedelta(minutes=1) assert Timedelta("1 minutes") == timedelta(minutes=1) assert Timedelta("1 s") == timedelta(seconds=1) From 2abd0eda8807ab620bcb02d741c68262a9fd104a Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Fri, 23 Oct 2020 01:21:39 +0200 Subject: [PATCH 17/22] Update parse_iso_format_string and tests that give warnings --- doc/source/whatsnew/v0.15.0.rst | 5 ++--- pandas/_libs/tslibs/timedeltas.pyx | 4 +++- pandas/tests/arithmetic/conftest.py | 6 +++--- pandas/tests/arithmetic/test_timedelta64.py | 6 +++--- pandas/tests/arrays/test_timedeltas.py | 2 +- pandas/tests/resample/test_datetime_index.py | 5 ++--- pandas/tests/scalar/interval/test_interval.py | 4 ++-- pandas/tests/scalar/timedelta/test_constructors.py | 14 +++++++------- pandas/tests/scalar/timedelta/test_timedelta.py | 2 +- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/source/whatsnew/v0.15.0.rst b/doc/source/whatsnew/v0.15.0.rst index f31861562f0a1..8c3046b24d66a 100644 --- a/doc/source/whatsnew/v0.15.0.rst +++ b/doc/source/whatsnew/v0.15.0.rst @@ -163,7 +163,7 @@ Access fields for a ``Timedelta`` .. ipython:: python - td = pd.Timedelta('1 hour 3m 15.5us') + td = pd.Timedelta('1 hour 3min 15.5us') td.seconds td.microseconds td.nanoseconds @@ -1030,12 +1030,11 @@ Other: If ``Period`` freq is ``D``, ``H``, ``T``, ``S``, ``L``, ``U``, ``N``, ``Timedelta``-like can be added if the result can have same freq. Otherwise, only the same ``offsets`` can be added. .. ipython:: python - :okwarning: idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') idx idx + pd.offsets.Hour(2) - idx + pd.Timedelta('120m') + idx + pd.Timedelta('120min') idx = pd.period_range('2014-07', periods=5, freq='M') idx diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 224c6f3328021..22b3014e0452d 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -645,9 +645,11 @@ cdef inline int64_t parse_iso_format_string(str ts) except? -1: else: neg = 1 elif c in ['W', 'D', 'H', 'M']: - unit.append(c) if c in ['H', 'M'] and len(number) > 2: raise ValueError(err_msg) + if c == 'M': + c = 'min' + unit.append(c) r = timedelta_from_spec(number, '0', unit) result += timedelta_as_neg(r, neg) diff --git a/pandas/tests/arithmetic/conftest.py b/pandas/tests/arithmetic/conftest.py index 47baf4e76f8c3..2af593070b5bc 100644 --- a/pandas/tests/arithmetic/conftest.py +++ b/pandas/tests/arithmetic/conftest.py @@ -113,9 +113,9 @@ def numeric_idx(request): @pytest.fixture( params=[ - pd.Timedelta("5m4s").to_pytimedelta(), - pd.Timedelta("5m4s"), - pd.Timedelta("5m4s").to_timedelta64(), + pd.Timedelta("5min4s").to_pytimedelta(), + pd.Timedelta("5min4s"), + pd.Timedelta("5min4s").to_timedelta64(), ], ids=lambda x: type(x).__name__, ) diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 5f556718ea0d3..5841f656c7b08 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1860,8 +1860,8 @@ def test_td64arr_floordiv_tdlike_scalar(self, two_hours, box_with_array): "scalar_td", [ timedelta(minutes=10, seconds=7), - Timedelta("10m7s"), - Timedelta("10m7s").to_timedelta64(), + Timedelta("10min7s"), + Timedelta("10min7s").to_timedelta64(), ], ids=lambda x: type(x).__name__, ) @@ -2060,7 +2060,7 @@ def test_td64arr_div_numeric_array(self, box_with_array, vector, any_real_dtype) tdser = Series(["59 Days", "59 Days", "NaT"], dtype="m8[ns]") vector = vector.astype(any_real_dtype) - expected = Series(["2.95D", "1D 23H 12m", "NaT"], dtype="timedelta64[ns]") + expected = Series(["2.95D", "1D 23H 12min", "NaT"], dtype="timedelta64[ns]") tdser = tm.box_expected(tdser, box_with_array) expected = tm.box_expected(expected, xbox) diff --git a/pandas/tests/arrays/test_timedeltas.py b/pandas/tests/arrays/test_timedeltas.py index 75d6f7d276518..40aa1a00bf3d5 100644 --- a/pandas/tests/arrays/test_timedeltas.py +++ b/pandas/tests/arrays/test_timedeltas.py @@ -271,7 +271,7 @@ def test_std(self): assert result is pd.NaT def test_median(self): - tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06m", "0H", "2H"]) + tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06min", "0H", "2H"]) arr = tdi.array result = arr.median(skipna=True) diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index 82935a5ee2359..bd06dd7496f83 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -759,7 +759,7 @@ def test_resample_origin(): resampled = ts.resample("5min", origin="1999-12-31 12:02:00").mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", offset="-3m").mean() + resampled = ts.resample("5min", offset="-3min").mean() tm.assert_index_equal(resampled.index, exp_rng) @@ -831,8 +831,7 @@ def test_resample_origin_with_tz(): resampled = ts.resample("5min", origin="1999-12-31 12:02:00+03:00").mean() tm.assert_index_equal(resampled.index, exp_rng) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - resampled = ts.resample("5min", origin="epoch", offset="2m").mean() + resampled = ts.resample("5min", origin="epoch", offset="2min").mean() tm.assert_index_equal(resampled.index, exp_rng) with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/scalar/interval/test_interval.py b/pandas/tests/scalar/interval/test_interval.py index 8ad9a2c7a9c70..5071c5cdec6c8 100644 --- a/pandas/tests/scalar/interval/test_interval.py +++ b/pandas/tests/scalar/interval/test_interval.py @@ -79,8 +79,8 @@ def test_hash(self, interval): (-np.inf, np.inf, np.inf), (Timedelta("0 days"), Timedelta("5 days"), Timedelta("5 days")), (Timedelta("10 days"), Timedelta("10 days"), Timedelta("0 days")), - (Timedelta("1H10M"), Timedelta("5H5M"), Timedelta("3H55M")), - (Timedelta("5S"), Timedelta("1H"), Timedelta("59M55S")), + (Timedelta("1H10min"), Timedelta("5H5min"), Timedelta("3H55min")), + (Timedelta("5S"), Timedelta("1H"), Timedelta("59min55S")), ], ) def test_length(self, left, right, expected): diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index bb4743a259d9c..e0d78dc01063a 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -62,19 +62,19 @@ def test_construction(): # combos assert Timedelta("10 days 1 hour") == timedelta(days=10, hours=1) assert Timedelta("10 days 1 h") == timedelta(days=10, hours=1) - assert Timedelta("10 days 1 h 1m 1s") == timedelta( + assert Timedelta("10 days 1 h 1min 1s") == timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1m 1s") == -timedelta( + assert Timedelta("-10 days 1 h 1min 1s") == -timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1m 1s") == -timedelta( + assert Timedelta("-10 days 1 h 1min 1s") == -timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1m 1s 3us") == -timedelta( + assert Timedelta("-10 days 1 h 1min 1s 3us") == -timedelta( days=10, hours=1, minutes=1, seconds=1, microseconds=3 ) - assert Timedelta("-10 days 1 h 1.5m 1s 3us") == -timedelta( + assert Timedelta("-10 days 1 h 1.5min 1s 3us") == -timedelta( days=10, hours=1, minutes=1, seconds=31, microseconds=3 ) @@ -82,11 +82,11 @@ def test_construction(): # (only allowed on the days) msg = "only leading negative signs are allowed" with pytest.raises(ValueError, match=msg): - Timedelta("-10 days -1 h 1.5m 1s 3us") + Timedelta("-10 days -1 h 1.5min 1s 3us") # only leading neg signs are allowed with pytest.raises(ValueError, match=msg): - Timedelta("10 days -1 h 1.5m 1s 3us") + Timedelta("10 days -1 h 1.5min 1s 3us") # no units specified msg = "no units specified" diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 8dd372aff9b62..d108554b456a5 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -309,7 +309,7 @@ def test_timedelta_conversions(self): def test_to_numpy_alias(self): # GH 24653: alias .to_numpy() for scalars - td = Timedelta("10m7s") + td = Timedelta("10min7s") assert td.to_timedelta64() == td.to_numpy() @pytest.mark.parametrize( From 8701f26bf768c63065abff66b8a008c62b667a7d Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 24 Oct 2020 19:44:15 +0200 Subject: [PATCH 18/22] Replace ipython directives with code-blocks in whatsnew v0.15.0 --- doc/source/whatsnew/v0.15.0.rst | 51 ++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/doc/source/whatsnew/v0.15.0.rst b/doc/source/whatsnew/v0.15.0.rst index 8c3046b24d66a..be55d6a7e56ca 100644 --- a/doc/source/whatsnew/v0.15.0.rst +++ b/doc/source/whatsnew/v0.15.0.rst @@ -161,12 +161,18 @@ Construct a scalar Access fields for a ``Timedelta`` -.. ipython:: python +.. code-block:: ipython + + In [14]: td = pd.Timedelta('1 hour 3m 15.5us') + + In [15]: td.seconds + Out[15]: 3780 + + In [16]: td.microseconds + Out[16]: 15 - td = pd.Timedelta('1 hour 3min 15.5us') - td.seconds - td.microseconds - td.nanoseconds + In [17]: td.nanoseconds + Out[17]: 500 Construct a ``TimedeltaIndex`` @@ -1029,16 +1035,35 @@ Other: If ``Period`` freq is ``D``, ``H``, ``T``, ``S``, ``L``, ``U``, ``N``, ``Timedelta``-like can be added if the result can have same freq. Otherwise, only the same ``offsets`` can be added. - .. ipython:: python + .. code-block:: ipython - idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') - idx - idx + pd.offsets.Hour(2) - idx + pd.Timedelta('120min') + In [104]: idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') - idx = pd.period_range('2014-07', periods=5, freq='M') - idx - idx + pd.offsets.MonthEnd(3) + In [105]: idx + Out[105]: + PeriodIndex(['2014-07-01 09:00', '2014-07-01 10:00', '2014-07-01 11:00', + '2014-07-01 12:00', '2014-07-01 13:00'], + dtype='period[H]', freq='H') + + In [106]: idx + pd.offsets.Hour(2) + Out[106]: + PeriodIndex(['2014-07-01 11:00', '2014-07-01 12:00', '2014-07-01 13:00', + '2014-07-01 14:00', '2014-07-01 15:00'], + dtype='period[H]', freq='H') + + In [107]: idx + pd.Timedelta('120m') + Out[107]: + PeriodIndex(['2014-07-01 11:00', '2014-07-01 12:00', '2014-07-01 13:00', + '2014-07-01 14:00', '2014-07-01 15:00'], + dtype='period[H]', freq='H') + + In [108]: idx = pd.period_range('2014-07', periods=5, freq='M') + + In [109]: idx + Out[109]: PeriodIndex(['2014-07', '2014-08', '2014-09', '2014-10', '2014-11'], dtype='period[M]', freq='M') + + In [110]: idx + pd.offsets.MonthEnd(3) + Out[110]: PeriodIndex(['2014-10', '2014-11', '2014-12', '2015-01', '2015-02'], dtype='period[M]', freq='M') - Added experimental compatibility with ``openpyxl`` for versions >= 2.0. The ``DataFrame.to_excel`` method ``engine`` keyword now recognizes ``openpyxl1`` and ``openpyxl2`` From 0cc6dff2a020a569a396f85dc5f0f125eef2947b Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Mon, 26 Oct 2020 23:07:12 +0100 Subject: [PATCH 19/22] Update newly added test --- pandas/tests/arrays/test_timedeltas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/arrays/test_timedeltas.py b/pandas/tests/arrays/test_timedeltas.py index e732545af3499..0e15137c0b4d9 100644 --- a/pandas/tests/arrays/test_timedeltas.py +++ b/pandas/tests/arrays/test_timedeltas.py @@ -336,7 +336,7 @@ def test_median(self): assert result is pd.NaT def test_mean(self): - tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06m", "0H", "2H"]) + tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06min", "0H", "2H"]) arr = tdi._data # manually verified result From 71f801ee98ef8d5c54b31336cbe95a0d82fe197b Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Wed, 28 Oct 2020 11:50:45 +0100 Subject: [PATCH 20/22] Update test to prevent depr warning --- pandas/tests/series/methods/test_shift.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/series/methods/test_shift.py b/pandas/tests/series/methods/test_shift.py index 4b23820caeeb4..d38d70abba923 100644 --- a/pandas/tests/series/methods/test_shift.py +++ b/pandas/tests/series/methods/test_shift.py @@ -32,7 +32,7 @@ def test_shift_always_copy(self, ser, shift_size): # GH22397 assert ser.shift(shift_size) is not ser - @pytest.mark.parametrize("move_by_freq", [pd.Timedelta("1D"), pd.Timedelta("1M")]) + @pytest.mark.parametrize("move_by_freq", [pd.Timedelta("1D"), pd.Timedelta("1min")]) def test_datetime_shift_always_copy(self, move_by_freq): # GH#22397 ser = Series(range(5), index=date_range("2017", periods=5)) From e01f75dcbd77eca4b4862326a0a6711f8df8a060 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 31 Oct 2020 16:23:32 +0100 Subject: [PATCH 21/22] Revert the depr of lowercase m --- doc/source/whatsnew/v0.15.0.rst | 51 +++++-------------- doc/source/whatsnew/v1.2.0.rst | 2 +- pandas/_libs/tslibs/timedeltas.pyx | 5 +- pandas/core/tools/timedeltas.py | 2 +- pandas/tests/arithmetic/conftest.py | 6 +-- pandas/tests/arithmetic/test_timedelta64.py | 6 +-- pandas/tests/arrays/test_timedeltas.py | 4 +- pandas/tests/resample/test_datetime_index.py | 4 +- .../scalar/timedelta/test_constructors.py | 16 +++--- .../tests/scalar/timedelta/test_timedelta.py | 32 +++++------- pandas/tests/tools/test_to_timedelta.py | 4 +- 11 files changed, 51 insertions(+), 81 deletions(-) diff --git a/doc/source/whatsnew/v0.15.0.rst b/doc/source/whatsnew/v0.15.0.rst index be55d6a7e56ca..28dbe1e73c8af 100644 --- a/doc/source/whatsnew/v0.15.0.rst +++ b/doc/source/whatsnew/v0.15.0.rst @@ -161,18 +161,12 @@ Construct a scalar Access fields for a ``Timedelta`` -.. code-block:: ipython - - In [14]: td = pd.Timedelta('1 hour 3m 15.5us') - - In [15]: td.seconds - Out[15]: 3780 - - In [16]: td.microseconds - Out[16]: 15 +.. ipython:: python - In [17]: td.nanoseconds - Out[17]: 500 + td = pd.Timedelta('1 hour 3m 15.5us') + td.seconds + td.microseconds + td.nanoseconds Construct a ``TimedeltaIndex`` @@ -1035,35 +1029,16 @@ Other: If ``Period`` freq is ``D``, ``H``, ``T``, ``S``, ``L``, ``U``, ``N``, ``Timedelta``-like can be added if the result can have same freq. Otherwise, only the same ``offsets`` can be added. - .. code-block:: ipython - - In [104]: idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') + .. ipython:: ipython - In [105]: idx - Out[105]: - PeriodIndex(['2014-07-01 09:00', '2014-07-01 10:00', '2014-07-01 11:00', - '2014-07-01 12:00', '2014-07-01 13:00'], - dtype='period[H]', freq='H') - - In [106]: idx + pd.offsets.Hour(2) - Out[106]: - PeriodIndex(['2014-07-01 11:00', '2014-07-01 12:00', '2014-07-01 13:00', - '2014-07-01 14:00', '2014-07-01 15:00'], - dtype='period[H]', freq='H') - - In [107]: idx + pd.Timedelta('120m') - Out[107]: - PeriodIndex(['2014-07-01 11:00', '2014-07-01 12:00', '2014-07-01 13:00', - '2014-07-01 14:00', '2014-07-01 15:00'], - dtype='period[H]', freq='H') - - In [108]: idx = pd.period_range('2014-07', periods=5, freq='M') - - In [109]: idx - Out[109]: PeriodIndex(['2014-07', '2014-08', '2014-09', '2014-10', '2014-11'], dtype='period[M]', freq='M') + idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') + idx + idx + pd.offsets.Hour(2) + idx + pd.Timedelta('120m') - In [110]: idx + pd.offsets.MonthEnd(3) - Out[110]: PeriodIndex(['2014-10', '2014-11', '2014-12', '2015-01', '2015-02'], dtype='period[M]', freq='M') + idx = pd.period_range('2014-07', periods=5, freq='M') + idx + idx + pd.offsets.MonthEnd(3) - Added experimental compatibility with ``openpyxl`` for versions >= 2.0. The ``DataFrame.to_excel`` method ``engine`` keyword now recognizes ``openpyxl1`` and ``openpyxl2`` diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 514d7ab082917..d75368bee42c8 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -329,7 +329,7 @@ Deprecations - :meth:`Rolling.count` with ``min_periods=None`` will default to the size of the window in a future version (:issue:`31302`) - Deprecated slice-indexing on timezone-aware :class:`DatetimeIndex` with naive ``datetime`` objects, to match scalar indexing behavior (:issue:`36148`) - :meth:`Index.ravel` returning a ``np.ndarray`` is deprecated, in the future this will return a view on the same index (:issue:`19956`) -- Deprecate use of strings denoting units with 'M', 'Y', 'm' or 'y' in :func:`~pandas.to_timedelta` (:issue:`36666`) +- Deprecate use of strings denoting units with 'M', 'Y' or 'y' in :func:`~pandas.to_timedelta` (:issue:`36666`) .. --------------------------------------------------------------------------- diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index d9ccc8caa21d2..45f32d92c7a74 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,5 +1,4 @@ import collections -import re import warnings import cython @@ -469,9 +468,9 @@ cdef inline timedelta_from_spec(object number, object frac, object unit): try: unit = ''.join(unit) - if unit in ["M", "Y", "m", "y"]: + if unit in ["M", "Y", "y"]: warnings.warn( - "Units 'M', 'Y', 'm' and 'y' do not represent unambiguous " + "Units 'M', 'Y' and 'y' do not represent unambiguous " "timedelta values and will be removed in a future version", FutureWarning, stacklevel=2, diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 387a3ae0ba0eb..e8faebd6b2542 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -28,7 +28,7 @@ def to_timedelta(arg, unit=None, errors="raise"): The data to be converted to timedelta. .. deprecated:: 1.2 - Strings with units 'M', 'Y', 'm' and 'y' do not represent + Strings with units 'M', 'Y' and 'y' do not represent unambiguous timedelta values and will be removed in a future version unit : str, optional diff --git a/pandas/tests/arithmetic/conftest.py b/pandas/tests/arithmetic/conftest.py index 2af593070b5bc..47baf4e76f8c3 100644 --- a/pandas/tests/arithmetic/conftest.py +++ b/pandas/tests/arithmetic/conftest.py @@ -113,9 +113,9 @@ def numeric_idx(request): @pytest.fixture( params=[ - pd.Timedelta("5min4s").to_pytimedelta(), - pd.Timedelta("5min4s"), - pd.Timedelta("5min4s").to_timedelta64(), + pd.Timedelta("5m4s").to_pytimedelta(), + pd.Timedelta("5m4s"), + pd.Timedelta("5m4s").to_timedelta64(), ], ids=lambda x: type(x).__name__, ) diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 2aa66db954d5d..31c7a17fd9ef5 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1856,8 +1856,8 @@ def test_td64arr_floordiv_tdlike_scalar(self, two_hours, box_with_array): "scalar_td", [ timedelta(minutes=10, seconds=7), - Timedelta("10min7s"), - Timedelta("10min7s").to_timedelta64(), + Timedelta("10m7s"), + Timedelta("10m7s").to_timedelta64(), ], ids=lambda x: type(x).__name__, ) @@ -2056,7 +2056,7 @@ def test_td64arr_div_numeric_array(self, box_with_array, vector, any_real_dtype) tdser = Series(["59 Days", "59 Days", "NaT"], dtype="m8[ns]") vector = vector.astype(any_real_dtype) - expected = Series(["2.95D", "1D 23H 12min", "NaT"], dtype="timedelta64[ns]") + expected = Series(["2.95D", "1D 23H 12m", "NaT"], dtype="timedelta64[ns]") tdser = tm.box_expected(tdser, box_with_array) expected = tm.box_expected(expected, xbox) diff --git a/pandas/tests/arrays/test_timedeltas.py b/pandas/tests/arrays/test_timedeltas.py index bc10c41e637ea..c0567209ff91b 100644 --- a/pandas/tests/arrays/test_timedeltas.py +++ b/pandas/tests/arrays/test_timedeltas.py @@ -329,7 +329,7 @@ def test_std(self, add): assert result is pd.NaT def test_median(self): - tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06min", "0H", "2H"]) + tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06m", "0H", "2H"]) arr = tdi.array result = arr.median(skipna=True) @@ -348,7 +348,7 @@ def test_median(self): assert result is pd.NaT def test_mean(self): - tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06min", "0H", "2H"]) + tdi = pd.TimedeltaIndex(["0H", "3H", "NaT", "5H06m", "0H", "2H"]) arr = tdi._data # manually verified result diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index 4a85ff081a77c..cead7785198a8 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -752,14 +752,14 @@ def test_resample_origin(): resampled = ts.resample("5min", origin=offset_timestamp).mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", origin="epoch", offset="2min").mean() + resampled = ts.resample("5min", origin="epoch", offset="2m").mean() tm.assert_index_equal(resampled.index, exp_rng) # origin of '1999-31-12 12:02:00' should be equivalent for this case resampled = ts.resample("5min", origin="1999-12-31 12:02:00").mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", offset="-3min").mean() + resampled = ts.resample("5min", offset="-3m").mean() tm.assert_index_equal(resampled.index, exp_rng) diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index e0d78dc01063a..2eab416ec5f67 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -40,8 +40,8 @@ def test_construction(): assert Timedelta("1 hr") == timedelta(hours=1) assert Timedelta("1 hours") == timedelta(hours=1) assert Timedelta("-1 hours") == -timedelta(hours=1) - assert Timedelta("1 min") == timedelta(minutes=1) - assert Timedelta("1.5 min") == timedelta(seconds=90) + assert Timedelta("1 m") == timedelta(minutes=1) + assert Timedelta("1.5 m") == timedelta(seconds=90) assert Timedelta("1 minute") == timedelta(minutes=1) assert Timedelta("1 minutes") == timedelta(minutes=1) assert Timedelta("1 s") == timedelta(seconds=1) @@ -62,19 +62,19 @@ def test_construction(): # combos assert Timedelta("10 days 1 hour") == timedelta(days=10, hours=1) assert Timedelta("10 days 1 h") == timedelta(days=10, hours=1) - assert Timedelta("10 days 1 h 1min 1s") == timedelta( + assert Timedelta("10 days 1 h 1m 1s") == timedelta( days=10, hours=1, minutes=1, seconds=1 ) assert Timedelta("-10 days 1 h 1min 1s") == -timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1min 1s") == -timedelta( + assert Timedelta("-10 days 1 h 1m 1s") == -timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1min 1s 3us") == -timedelta( + assert Timedelta("-10 days 1 h 1m 1s 3us") == -timedelta( days=10, hours=1, minutes=1, seconds=1, microseconds=3 ) - assert Timedelta("-10 days 1 h 1.5min 1s 3us") == -timedelta( + assert Timedelta("-10 days 1 h 1.5m 1s 3us") == -timedelta( days=10, hours=1, minutes=1, seconds=31, microseconds=3 ) @@ -82,11 +82,11 @@ def test_construction(): # (only allowed on the days) msg = "only leading negative signs are allowed" with pytest.raises(ValueError, match=msg): - Timedelta("-10 days -1 h 1.5min 1s 3us") + Timedelta("-10 days -1 h 1.5m 1s 3us") # only leading neg signs are allowed with pytest.raises(ValueError, match=msg): - Timedelta("10 days -1 h 1.5min 1s 3us") + Timedelta("10 days -1 h 1.5m 1s 3us") # no units specified msg = "no units specified" diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index d108554b456a5..89b45b7266daa 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -160,11 +160,11 @@ def test_nat_converters(self): assert result.astype("int64") == iNaT @pytest.mark.parametrize( - "unit, np_unit, warning", - [(value, "W", False) for value in ["W", "w"]] - + [(value, "D", False) for value in ["D", "d", "days", "day", "Days", "Day"]] + "unit, np_unit", + [(value, "W") for value in ["W", "w"]] + + [(value, "D") for value in ["D", "d", "days", "day", "Days", "Day"]] + [ - (value, "m", FutureWarning if value == "m" else False) # type: ignore[misc] + (value, "m") for value in [ "m", "minute", @@ -178,7 +178,7 @@ def test_nat_converters(self): ] ] + [ - (value, "s", False) + (value, "s") for value in [ "s", "seconds", @@ -191,7 +191,7 @@ def test_nat_converters(self): ] ] + [ - (value, "ms", False) + (value, "ms") for value in [ "ms", "milliseconds", @@ -208,7 +208,7 @@ def test_nat_converters(self): ] ] + [ - (value, "us", False) + (value, "us") for value in [ "us", "microseconds", @@ -225,7 +225,7 @@ def test_nat_converters(self): ] ] + [ - (value, "ns", False) + (value, "ns") for value in [ "ns", "nanoseconds", @@ -243,7 +243,7 @@ def test_nat_converters(self): ], ) @pytest.mark.parametrize("wrapper", [np.array, list, pd.Index]) - def test_unit_parser(self, unit, np_unit, wrapper, warning): + def test_unit_parser(self, unit, np_unit, wrapper): # validate all units, GH 6855, GH 21762 # array-likes expected = TimedeltaIndex( @@ -255,11 +255,9 @@ def test_unit_parser(self, unit, np_unit, wrapper, warning): tm.assert_index_equal(result, expected) str_repr = [f"{x}{unit}" for x in np.arange(5)] - with tm.assert_produces_warning(warning, check_stacklevel=False): - result = to_timedelta(wrapper(str_repr)) + result = to_timedelta(wrapper(str_repr)) tm.assert_index_equal(result, expected) - with tm.assert_produces_warning(warning, check_stacklevel=False): - result = to_timedelta(wrapper(str_repr)) + result = to_timedelta(wrapper(str_repr)) tm.assert_index_equal(result, expected) # scalar @@ -269,11 +267,9 @@ def test_unit_parser(self, unit, np_unit, wrapper, warning): result = Timedelta(2, unit=unit) assert result == expected - with tm.assert_produces_warning(warning, check_stacklevel=False): - result = to_timedelta(f"2{unit}") + result = to_timedelta(f"2{unit}") assert result == expected - with tm.assert_produces_warning(warning, check_stacklevel=False): - result = Timedelta(f"2{unit}") + result = Timedelta(f"2{unit}") assert result == expected @pytest.mark.parametrize("unit", ["Y", "y", "M"]) @@ -309,7 +305,7 @@ def test_timedelta_conversions(self): def test_to_numpy_alias(self): # GH 24653: alias .to_numpy() for scalars - td = Timedelta("10min7s") + td = Timedelta("10m7s") assert td.to_timedelta64() == td.to_numpy() @pytest.mark.parametrize( diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index cbb407f759253..8e48295c533cc 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -128,10 +128,10 @@ def test_to_timedelta_invalid(self): ("1 M", FutureWarning), ("1Y", FutureWarning), ("1 Y", FutureWarning), - ("1m", FutureWarning), - ("1 m", FutureWarning), ("1y", FutureWarning), ("1 y", FutureWarning), + ("1m", None), + ("1 m", None), ("1 day", None), ("2day", None), ], From 52779434d5f79cad9f31b87acef1154563cf69f1 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Sat, 31 Oct 2020 16:26:46 +0100 Subject: [PATCH 22/22] Revert more depr of m --- doc/source/whatsnew/v0.15.0.rst | 2 +- pandas/tests/resample/test_datetime_index.py | 2 +- pandas/tests/scalar/timedelta/test_constructors.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v0.15.0.rst b/doc/source/whatsnew/v0.15.0.rst index 28dbe1e73c8af..1f054930b3709 100644 --- a/doc/source/whatsnew/v0.15.0.rst +++ b/doc/source/whatsnew/v0.15.0.rst @@ -1029,7 +1029,7 @@ Other: If ``Period`` freq is ``D``, ``H``, ``T``, ``S``, ``L``, ``U``, ``N``, ``Timedelta``-like can be added if the result can have same freq. Otherwise, only the same ``offsets`` can be added. - .. ipython:: ipython + .. ipython:: python idx = pd.period_range('2014-07-01 09:00', periods=5, freq='H') idx diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index cead7785198a8..7681807b60989 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -831,7 +831,7 @@ def test_resample_origin_with_tz(): resampled = ts.resample("5min", origin="1999-12-31 12:02:00+03:00").mean() tm.assert_index_equal(resampled.index, exp_rng) - resampled = ts.resample("5min", origin="epoch", offset="2min").mean() + resampled = ts.resample("5min", origin="epoch", offset="2m").mean() tm.assert_index_equal(resampled.index, exp_rng) with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index 2eab416ec5f67..06bdb8a6cf0a2 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -65,7 +65,7 @@ def test_construction(): assert Timedelta("10 days 1 h 1m 1s") == timedelta( days=10, hours=1, minutes=1, seconds=1 ) - assert Timedelta("-10 days 1 h 1min 1s") == -timedelta( + assert Timedelta("-10 days 1 h 1m 1s") == -timedelta( days=10, hours=1, minutes=1, seconds=1 ) assert Timedelta("-10 days 1 h 1m 1s") == -timedelta(