Skip to content

Commit 4e5576d

Browse files
authored
DEPR: errors='ignore' (#55734)
* DEPR: errors='ignore' * update docs * code-block
1 parent ba43224 commit 4e5576d

16 files changed

+159
-79
lines changed

doc/source/user_guide/basics.rst

-17
Original file line numberDiff line numberDiff line change
@@ -2261,23 +2261,6 @@ non-conforming elements intermixed that you want to represent as missing:
22612261
m = ["apple", pd.Timedelta("1day")]
22622262
pd.to_timedelta(m, errors="coerce")
22632263
2264-
The ``errors`` parameter has a third option of ``errors='ignore'``, which will simply return the passed in data if it
2265-
encounters any errors with the conversion to a desired data type:
2266-
2267-
.. ipython:: python
2268-
:okwarning:
2269-
2270-
import datetime
2271-
2272-
m = ["apple", datetime.datetime(2016, 3, 2)]
2273-
pd.to_datetime(m, errors="ignore")
2274-
2275-
m = ["apple", 2, 3]
2276-
pd.to_numeric(m, errors="ignore")
2277-
2278-
m = ["apple", pd.Timedelta("1day")]
2279-
pd.to_timedelta(m, errors="ignore")
2280-
22812264
In addition to object conversion, :meth:`~pandas.to_numeric` provides another argument ``downcast``, which gives the
22822265
option of downcasting the newly (or already) numeric data to a smaller dtype, which can conserve memory:
22832266

doc/source/user_guide/timeseries.rst

-6
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,6 @@ The default behavior, ``errors='raise'``, is to raise when unparsable:
294294
295295
pd.to_datetime(['2009/07/31', 'asd'], errors='raise')
296296
297-
Pass ``errors='ignore'`` to return the original input when unparsable:
298-
299-
.. ipython:: python
300-
301-
pd.to_datetime(["2009/07/31", "asd"], errors="ignore")
302-
303297
Pass ``errors='coerce'`` to convert unparsable data to ``NaT`` (not a time):
304298

305299
.. ipython:: python

doc/source/whatsnew/v0.17.0.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,10 @@ Of course you can coerce this as well.
632632
633633
To keep the previous behavior, you can use ``errors='ignore'``:
634634

635-
.. ipython:: python
635+
.. code-block:: ipython
636636
637-
pd.to_datetime(["2009-07-31", "asd"], errors="ignore")
637+
In [4]: pd.to_datetime(["2009-07-31", "asd"], errors="ignore")
638+
Out[4]: Index(['2009-07-31', 'asd'], dtype='object')
638639
639640
Furthermore, ``pd.to_timedelta`` has gained a similar API, of ``errors='raise'|'ignore'|'coerce'``, and the ``coerce`` keyword
640641
has been deprecated in favor of ``errors='coerce'``.

doc/source/whatsnew/v2.2.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,13 @@ Other Deprecations
284284
- Deprecated strings ``H``, ``S``, ``U``, and ``N`` denoting units in :func:`to_timedelta` (:issue:`52536`)
285285
- Deprecated strings ``H``, ``T``, ``S``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`52536`)
286286
- Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Second`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`52536`)
287+
- Deprecated the ``errors="ignore"`` option in :func:`to_datetime`, :func:`to_timedelta`, and :func:`to_numeric`; explicitly catch exceptions instead (:issue:`54467`)
287288
- Deprecated the ``fastpath`` keyword in the :class:`Series` constructor (:issue:`20110`)
288289
- Deprecated the extension test classes ``BaseNoReduceTests``, ``BaseBooleanReduceTests``, and ``BaseNumericReduceTests``, use ``BaseReduceTests`` instead (:issue:`54663`)
289290
- Deprecated the option ``mode.data_manager`` and the ``ArrayManager``; only the ``BlockManager`` will be available in future versions (:issue:`55043`)
290291
- Deprecated the previous implementation of :class:`DataFrame.stack`; specify ``future_stack=True`` to adopt the future version (:issue:`53515`)
291292
- Deprecating downcasting the results of :meth:`DataFrame.fillna`, :meth:`Series.fillna`, :meth:`DataFrame.ffill`, :meth:`Series.ffill`, :meth:`DataFrame.bfill`, :meth:`Series.bfill` in object-dtype cases. To opt in to the future version, use ``pd.set_option("future.no_silent_downcasting", True)`` (:issue:`54261`)
293+
-
292294

293295
.. ---------------------------------------------------------------------------
294296
.. _whatsnew_220.performance:

pandas/core/reshape/melt.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,11 @@ def melt_stub(df, stub: str, i, j, value_vars, sep: str):
498498
newdf[j] = newdf[j].str.replace(re.escape(stub + sep), "", regex=True)
499499

500500
# GH17627 Cast numerics suffixes to int/float
501-
newdf[j] = to_numeric(newdf[j], errors="ignore")
501+
try:
502+
newdf[j] = to_numeric(newdf[j])
503+
except (TypeError, ValueError, OverflowError):
504+
# TODO: anything else to catch?
505+
pass
502506

503507
return newdf.set_index(i + [j])
504508

pandas/core/tools/datetimes.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -980,16 +980,9 @@ def to_datetime(
980980
981981
**Non-convertible date/times**
982982
983-
If a date does not meet the `timestamp limitations
984-
<https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html
985-
#timeseries-timestamp-limits>`_, passing ``errors='ignore'``
986-
will return the original input instead of raising any exception.
987-
988983
Passing ``errors='coerce'`` will force an out-of-bounds date to :const:`NaT`,
989984
in addition to forcing non-dates (or non-parseable dates) to :const:`NaT`.
990985
991-
>>> pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')
992-
'13000101'
993986
>>> pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')
994987
NaT
995988
@@ -1079,6 +1072,16 @@ def to_datetime(
10791072
"You can safely remove this argument.",
10801073
stacklevel=find_stack_level(),
10811074
)
1075+
if errors == "ignore":
1076+
# GH#54467
1077+
warnings.warn(
1078+
"errors='ignore' is deprecated and will raise in a future version. "
1079+
"Use to_datetime without passing `errors` and catch exceptions "
1080+
"explicitly instead",
1081+
FutureWarning,
1082+
stacklevel=find_stack_level(),
1083+
)
1084+
10821085
if arg is None:
10831086
return None
10841087

pandas/core/tools/numeric.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
TYPE_CHECKING,
55
Literal,
66
)
7+
import warnings
78

89
import numpy as np
910

1011
from pandas._libs import lib
12+
from pandas.util._exceptions import find_stack_level
1113
from pandas.util._validators import check_dtype_backend
1214

1315
from pandas.core.dtypes.cast import maybe_downcast_numeric
@@ -68,6 +70,11 @@ def to_numeric(
6870
- If 'raise', then invalid parsing will raise an exception.
6971
- If 'coerce', then invalid parsing will be set as NaN.
7072
- If 'ignore', then invalid parsing will return the input.
73+
74+
.. versionchanged:: 2.2
75+
76+
"ignore" is deprecated. Catch exceptions explicitly instead.
77+
7178
downcast : str, default None
7279
Can be 'integer', 'signed', 'unsigned', or 'float'.
7380
If not None, and if the data has been successfully cast to a
@@ -134,12 +141,6 @@ def to_numeric(
134141
2 -3
135142
dtype: int8
136143
>>> s = pd.Series(['apple', '1.0', '2', -3])
137-
>>> pd.to_numeric(s, errors='ignore')
138-
0 apple
139-
1 1.0
140-
2 2
141-
3 -3
142-
dtype: object
143144
>>> pd.to_numeric(s, errors='coerce')
144145
0 NaN
145146
1 1.0
@@ -167,6 +168,15 @@ def to_numeric(
167168

168169
if errors not in ("ignore", "raise", "coerce"):
169170
raise ValueError("invalid error value specified")
171+
if errors == "ignore":
172+
# GH#54467
173+
warnings.warn(
174+
"errors='ignore' is deprecated and will raise in a future version. "
175+
"Use to_numeric without passing `errors` and catch exceptions "
176+
"explicitly instead",
177+
FutureWarning,
178+
stacklevel=find_stack_level(),
179+
)
170180

171181
check_dtype_backend(dtype_backend)
172182

pandas/core/tools/timedeltas.py

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
TYPE_CHECKING,
88
overload,
99
)
10+
import warnings
1011

1112
import numpy as np
1213

@@ -20,6 +21,7 @@
2021
disallow_ambiguous_unit,
2122
parse_timedelta_unit,
2223
)
24+
from pandas.util._exceptions import find_stack_level
2325

2426
from pandas.core.dtypes.common import is_list_like
2527
from pandas.core.dtypes.dtypes import ArrowDtype
@@ -183,6 +185,15 @@ def to_timedelta(
183185

184186
if errors not in ("ignore", "raise", "coerce"):
185187
raise ValueError("errors must be one of 'ignore', 'raise', or 'coerce'.")
188+
if errors == "ignore":
189+
# GH#54467
190+
warnings.warn(
191+
"errors='ignore' is deprecated and will raise in a future version. "
192+
"Use to_timedelta without passing `errors` and catch exceptions "
193+
"explicitly instead",
194+
FutureWarning,
195+
stacklevel=find_stack_level(),
196+
)
186197

187198
if arg is None:
188199
return arg

pandas/core/tools/times.py

+11
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
time,
66
)
77
from typing import TYPE_CHECKING
8+
import warnings
89

910
import numpy as np
1011

1112
from pandas._libs.lib import is_list_like
13+
from pandas.util._exceptions import find_stack_level
1214

1315
from pandas.core.dtypes.generic import (
1416
ABCIndex,
@@ -52,6 +54,15 @@ def to_time(
5254
-------
5355
datetime.time
5456
"""
57+
if errors == "ignore":
58+
# GH#54467
59+
warnings.warn(
60+
"errors='ignore' is deprecated and will raise in a future version. "
61+
"Use to_time without passing `errors` and catch exceptions "
62+
"explicitly instead",
63+
FutureWarning,
64+
stacklevel=find_stack_level(),
65+
)
5566

5667
def _convert_listlike(arg, format):
5768
if isinstance(arg, (list, tuple)):

pandas/io/parsers/base_parser.py

+32-20
Original file line numberDiff line numberDiff line change
@@ -1150,14 +1150,19 @@ def converter(*date_cols, col: Hashable):
11501150
".*parsing datetimes with mixed time zones will raise an error",
11511151
category=FutureWarning,
11521152
)
1153-
result = tools.to_datetime(
1154-
ensure_object(strs),
1155-
format=date_fmt,
1156-
utc=False,
1157-
dayfirst=dayfirst,
1158-
errors="ignore",
1159-
cache=cache_dates,
1160-
)
1153+
str_objs = ensure_object(strs)
1154+
try:
1155+
result = tools.to_datetime(
1156+
str_objs,
1157+
format=date_fmt,
1158+
utc=False,
1159+
dayfirst=dayfirst,
1160+
cache=cache_dates,
1161+
)
1162+
except (ValueError, TypeError):
1163+
# test_usecols_with_parse_dates4
1164+
return str_objs
1165+
11611166
if isinstance(result, DatetimeIndex):
11621167
arr = result.to_numpy()
11631168
arr.flags.writeable = True
@@ -1172,31 +1177,38 @@ def converter(*date_cols, col: Hashable):
11721177
"will raise an error",
11731178
category=FutureWarning,
11741179
)
1175-
result = tools.to_datetime(
1176-
date_parser(
1177-
*(unpack_if_single_element(arg) for arg in date_cols)
1178-
),
1179-
errors="ignore",
1180-
cache=cache_dates,
1180+
pre_parsed = date_parser(
1181+
*(unpack_if_single_element(arg) for arg in date_cols)
11811182
)
1183+
try:
1184+
result = tools.to_datetime(
1185+
pre_parsed,
1186+
cache=cache_dates,
1187+
)
1188+
except (ValueError, TypeError):
1189+
# test_read_csv_with_custom_date_parser
1190+
result = pre_parsed
11821191
if isinstance(result, datetime.datetime):
11831192
raise Exception("scalar parser")
11841193
return result
11851194
except Exception:
1195+
# e.g. test_datetime_fractional_seconds
11861196
with warnings.catch_warnings():
11871197
warnings.filterwarnings(
11881198
"ignore",
11891199
".*parsing datetimes with mixed time zones "
11901200
"will raise an error",
11911201
category=FutureWarning,
11921202
)
1193-
return tools.to_datetime(
1194-
parsing.try_parse_dates(
1195-
parsing.concat_date_cols(date_cols),
1196-
parser=date_parser,
1197-
),
1198-
errors="ignore",
1203+
pre_parsed = parsing.try_parse_dates(
1204+
parsing.concat_date_cols(date_cols),
1205+
parser=date_parser,
11991206
)
1207+
try:
1208+
return tools.to_datetime(pre_parsed)
1209+
except (ValueError, TypeError):
1210+
# TODO: not reached in tests 2023-10-27; needed?
1211+
return pre_parsed
12001212

12011213
return converter
12021214

pandas/io/sql.py

+6
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ def _handle_date_column(
105105
# Format can take on custom to_datetime argument values such as
106106
# {"errors": "coerce"} or {"dayfirst": True}
107107
error: DateTimeErrorChoices = format.pop("errors", None) or "ignore"
108+
if error == "ignore":
109+
try:
110+
return to_datetime(col, **format)
111+
except (TypeError, ValueError):
112+
# TODO: not reached 2023-10-27; needed?
113+
return col
108114
return to_datetime(col, errors=error, **format)
109115
else:
110116
# Allow passing of formatting string for integers

pandas/tests/test_algos.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,9 @@ def test_value_counts_datetime_outofbounds(self):
12781278
tm.assert_series_equal(res, exp)
12791279

12801280
# GH 12424 # TODO: belongs elsewhere
1281-
res = to_datetime(Series(["2362-01-01", np.nan]), errors="ignore")
1281+
msg = "errors='ignore' is deprecated"
1282+
with tm.assert_produces_warning(FutureWarning, match=msg):
1283+
res = to_datetime(Series(["2362-01-01", np.nan]), errors="ignore")
12821284
exp = Series(["2362-01-01", np.nan], dtype=object)
12831285
tm.assert_series_equal(res, exp)
12841286

pandas/tests/tools/test_to_datetime.py

+19-5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
r"alongside this."
5858
)
5959

60+
pytestmark = pytest.mark.filterwarnings(
61+
"ignore:errors='ignore' is deprecated:FutureWarning"
62+
)
63+
6064

6165
@pytest.fixture(params=[True, False])
6266
def cache(request):
@@ -1228,7 +1232,9 @@ def test_to_datetime_tz_mixed(self, cache):
12281232
with pytest.raises(ValueError, match=msg):
12291233
to_datetime(arr, cache=cache)
12301234

1231-
result = to_datetime(arr, cache=cache, errors="ignore")
1235+
depr_msg = "errors='ignore' is deprecated"
1236+
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
1237+
result = to_datetime(arr, cache=cache, errors="ignore")
12321238
expected = Index(
12331239
[
12341240
Timestamp("2013-01-01 13:00:00-08:00"),
@@ -1474,11 +1480,15 @@ def test_datetime_invalid_index(self, values, format):
14741480
warn = UserWarning
14751481
else:
14761482
warn = None
1477-
with tm.assert_produces_warning(warn, match="Could not infer format"):
1483+
with tm.assert_produces_warning(
1484+
warn, match="Could not infer format", raise_on_extra_warnings=False
1485+
):
14781486
res = to_datetime(values, errors="ignore", format=format)
14791487
tm.assert_index_equal(res, Index(values))
14801488

1481-
with tm.assert_produces_warning(warn, match="Could not infer format"):
1489+
with tm.assert_produces_warning(
1490+
warn, match="Could not infer format", raise_on_extra_warnings=False
1491+
):
14821492
res = to_datetime(values, errors="coerce", format=format)
14831493
tm.assert_index_equal(res, DatetimeIndex([NaT] * len(values)))
14841494

@@ -1493,7 +1503,9 @@ def test_datetime_invalid_index(self, values, format):
14931503
]
14941504
)
14951505
with pytest.raises(ValueError, match=msg):
1496-
with tm.assert_produces_warning(warn, match="Could not infer format"):
1506+
with tm.assert_produces_warning(
1507+
warn, match="Could not infer format", raise_on_extra_warnings=False
1508+
):
14971509
to_datetime(values, errors="raise", format=format)
14981510

14991511
@pytest.mark.parametrize("utc", [True, None])
@@ -1662,7 +1674,9 @@ def test_to_datetime_malformed_no_raise(self, errors, expected):
16621674
# GH 28299
16631675
# GH 48633
16641676
ts_strings = ["200622-12-31", "111111-24-11"]
1665-
with tm.assert_produces_warning(UserWarning, match="Could not infer format"):
1677+
with tm.assert_produces_warning(
1678+
UserWarning, match="Could not infer format", raise_on_extra_warnings=False
1679+
):
16661680
result = to_datetime(ts_strings, errors=errors)
16671681
tm.assert_index_equal(result, expected)
16681682

0 commit comments

Comments
 (0)