Skip to content

Commit a730486

Browse files
authored
ENH: Allow performance warnings to be disabled (#56921)
* ENH: Allow performance warnings to be disabled * ENH: Allow performance warnings to be disabled * Add tests * fixup
1 parent 54d2033 commit a730486

39 files changed

+301
-217
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Other enhancements
3333
- :meth:`Styler.set_tooltips` provides alternative method to storing tooltips by using title attribute of td elements. (:issue:`56981`)
3434
- Allow dictionaries to be passed to :meth:`pandas.Series.str.replace` via ``pat`` parameter (:issue:`51748`)
3535
- Support passing a :class:`Series` input to :func:`json_normalize` that retains the :class:`Series` :class:`Index` (:issue:`51452`)
36+
- Users can globally disable any ``PerformanceWarning`` by setting the option ``mode.performance_warnings`` to ``False`` (:issue:`56920`)
3637
-
3738

3839
.. ---------------------------------------------------------------------------

pandas/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,6 +1983,16 @@ def indexer_ial(request):
19831983
return request.param
19841984

19851985

1986+
@pytest.fixture(params=[True, False])
1987+
def performance_warning(request) -> Iterator[bool | type[Warning]]:
1988+
"""
1989+
Fixture to check if performance warnings are enabled. Either produces
1990+
``PerformanceWarning`` if they are enabled, otherwise ``False``.
1991+
"""
1992+
with pd.option_context("mode.performance_warnings", request.param):
1993+
yield pd.errors.PerformanceWarning if request.param else False
1994+
1995+
19861996
@pytest.fixture
19871997
def using_infer_string() -> bool:
19881998
"""

pandas/core/arrays/arrow/_arrow_utils.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import numpy as np
66
import pyarrow
77

8+
from pandas._config.config import _get_option
9+
810
from pandas.errors import PerformanceWarning
911
from pandas.util._exceptions import find_stack_level
1012

@@ -14,10 +16,11 @@ def fallback_performancewarning(version: str | None = None) -> None:
1416
Raise a PerformanceWarning for falling back to ExtensionArray's
1517
non-pyarrow method
1618
"""
17-
msg = "Falling back on a non-pyarrow code path which may decrease performance."
18-
if version is not None:
19-
msg += f" Upgrade to pyarrow >={version} to possibly suppress this warning."
20-
warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level())
19+
if _get_option("performance_warnings"):
20+
msg = "Falling back on a non-pyarrow code path which may decrease performance."
21+
if version is not None:
22+
msg += f" Upgrade to pyarrow >={version} to possibly suppress this warning."
23+
warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level())
2124

2225

2326
def pyarrow_array_to_numpy_and_mask(

pandas/core/arrays/datetimelike.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import numpy as np
2222

23+
from pandas._config.config import _get_option
24+
2325
from pandas._libs import (
2426
algos,
2527
lib,
@@ -1332,12 +1334,13 @@ def _addsub_object_array(self, other: npt.NDArray[np.object_], op) -> np.ndarray
13321334
# If both 1D then broadcasting is unambiguous
13331335
return op(self, other[0])
13341336

1335-
warnings.warn(
1336-
"Adding/subtracting object-dtype array to "
1337-
f"{type(self).__name__} not vectorized.",
1338-
PerformanceWarning,
1339-
stacklevel=find_stack_level(),
1340-
)
1337+
if _get_option("performance_warnings"):
1338+
warnings.warn(
1339+
"Adding/subtracting object-dtype array to "
1340+
f"{type(self).__name__} not vectorized.",
1341+
PerformanceWarning,
1342+
stacklevel=find_stack_level(),
1343+
)
13411344

13421345
# Caller is responsible for broadcasting if necessary
13431346
assert self.shape == other.shape, (self.shape, other.shape)

pandas/core/arrays/datetimes.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import numpy as np
1717

18+
from pandas._config.config import _get_option
19+
1820
from pandas._libs import (
1921
lib,
2022
tslib,
@@ -818,11 +820,13 @@ def _add_offset(self, offset: BaseOffset) -> Self:
818820
# "dtype[Any] | type[Any] | _SupportsDType[dtype[Any]]"
819821
res_values = res_values.view(values.dtype) # type: ignore[arg-type]
820822
except NotImplementedError:
821-
warnings.warn(
822-
"Non-vectorized DateOffset being applied to Series or DatetimeIndex.",
823-
PerformanceWarning,
824-
stacklevel=find_stack_level(),
825-
)
823+
if _get_option("performance_warnings"):
824+
warnings.warn(
825+
"Non-vectorized DateOffset being applied to Series or "
826+
"DatetimeIndex.",
827+
PerformanceWarning,
828+
stacklevel=find_stack_level(),
829+
)
826830
res_values = self.astype("O") + offset
827831
# TODO(GH#55564): as_unit will be unnecessary
828832
result = type(self)._from_sequence(res_values).as_unit(self.unit)

pandas/core/arrays/sparse/array.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import numpy as np
2020

21+
from pandas._config.config import _get_option
22+
2123
from pandas._libs import lib
2224
import pandas._libs.sparse as splib
2325
from pandas._libs.sparse import (
@@ -1154,8 +1156,9 @@ def searchsorted(
11541156
side: Literal["left", "right"] = "left",
11551157
sorter: NumpySorter | None = None,
11561158
) -> npt.NDArray[np.intp] | np.intp:
1157-
msg = "searchsorted requires high memory usage."
1158-
warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level())
1159+
if _get_option("performance_warnings"):
1160+
msg = "searchsorted requires high memory usage."
1161+
warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level())
11591162
v = np.asarray(v)
11601163
return np.asarray(self, dtype=self.dtype.subtype).searchsorted(v, side, sorter)
11611164

pandas/core/arrays/string_arrow.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import numpy as np
1414

15+
from pandas._config.config import _get_option
16+
1517
from pandas._libs import (
1618
lib,
1719
missing as libmissing,
@@ -343,7 +345,8 @@ def _str_contains(
343345
self, pat, case: bool = True, flags: int = 0, na=np.nan, regex: bool = True
344346
):
345347
if flags:
346-
fallback_performancewarning()
348+
if _get_option("mode.performance_warnings"):
349+
fallback_performancewarning()
347350
return super()._str_contains(pat, case, flags, na, regex)
348351

349352
if regex:
@@ -403,7 +406,8 @@ def _str_replace(
403406
regex: bool = True,
404407
):
405408
if isinstance(pat, re.Pattern) or callable(repl) or not case or flags:
406-
fallback_performancewarning()
409+
if _get_option("mode.performance_warnings"):
410+
fallback_performancewarning()
407411
return super()._str_replace(pat, repl, n, case, flags, regex)
408412

409413
func = pc.replace_substring_regex if regex else pc.replace_substring

pandas/core/computation/align.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import numpy as np
1717

18+
from pandas._config.config import _get_option
19+
1820
from pandas.errors import PerformanceWarning
1921
from pandas.util._exceptions import find_stack_level
2022

@@ -124,7 +126,11 @@ def _align_core(terms):
124126
reindexer_size = len(reindexer)
125127

126128
ordm = np.log10(max(1, abs(reindexer_size - term_axis_size)))
127-
if ordm >= 1 and reindexer_size >= 10000:
129+
if (
130+
_get_option("performance_warnings")
131+
and ordm >= 1
132+
and reindexer_size >= 10000
133+
):
128134
w = (
129135
f"Alignment difference on axis {axis} is larger "
130136
f"than an order of magnitude on term {terms[i].name!r}, "

pandas/core/config_init.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,19 @@ def is_terminal() -> bool:
444444
validator=is_one_of_factory([None, "warn", "raise"]),
445445
)
446446

447+
performance_warnings = """
448+
: boolean
449+
Whether to show or hide PerformanceWarnings.
450+
"""
451+
452+
with cf.config_prefix("mode"):
453+
cf.register_option(
454+
"performance_warnings",
455+
True,
456+
performance_warnings,
457+
validator=is_bool,
458+
)
459+
447460

448461
string_storage_doc = """
449462
: string

pandas/core/dtypes/dtypes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import numpy as np
2222
import pytz
2323

24+
from pandas._config.config import _get_option
25+
2426
from pandas._libs import (
2527
lib,
2628
missing as libmissing,
@@ -2028,7 +2030,9 @@ def _get_common_dtype(self, dtypes: list[DtypeObj]) -> DtypeObj | None:
20282030

20292031
# np.nan isn't a singleton, so we may end up with multiple
20302032
# NaNs here, so we ignore the all NA case too.
2031-
if not (len(set(fill_values)) == 1 or isna(fill_values).all()):
2033+
if _get_option("performance_warnings") and (
2034+
not (len(set(fill_values)) == 1 or isna(fill_values).all())
2035+
):
20322036
warnings.warn(
20332037
"Concatenating sparse arrays with multiple fill "
20342038
f"values: '{fill_values}'. Picking the first and "

pandas/core/indexes/multi.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import numpy as np
2222

2323
from pandas._config import get_option
24+
from pandas._config.config import _get_option
2425

2526
from pandas._libs import (
2627
algos as libalgos,
@@ -2356,7 +2357,7 @@ def drop( # type: ignore[override]
23562357
step = loc.step if loc.step is not None else 1
23572358
inds.extend(range(loc.start, loc.stop, step))
23582359
elif com.is_bool_indexer(loc):
2359-
if self._lexsort_depth == 0:
2360+
if _get_option("performance_warnings") and self._lexsort_depth == 0:
23602361
warnings.warn(
23612362
"dropping on a non-lexsorted multi-index "
23622363
"without a level parameter may impact performance.",
@@ -3018,11 +3019,12 @@ def _maybe_to_slice(loc):
30183019
if not follow_key:
30193020
return slice(start, stop)
30203021

3021-
warnings.warn(
3022-
"indexing past lexsort depth may impact performance.",
3023-
PerformanceWarning,
3024-
stacklevel=find_stack_level(),
3025-
)
3022+
if _get_option("performance_warnings"):
3023+
warnings.warn(
3024+
"indexing past lexsort depth may impact performance.",
3025+
PerformanceWarning,
3026+
stacklevel=find_stack_level(),
3027+
)
30263028

30273029
loc = np.arange(start, stop, dtype=np.intp)
30283030

pandas/core/internals/managers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import numpy as np
2020

21+
from pandas._config.config import _get_option
22+
2123
from pandas._libs import (
2224
algos as libalgos,
2325
internals as libinternals,
@@ -1526,7 +1528,10 @@ def insert(self, loc: int, item: Hashable, value: ArrayLike, refs=None) -> None:
15261528

15271529
self._known_consolidated = False
15281530

1529-
if sum(not block.is_extension for block in self.blocks) > 100:
1531+
if (
1532+
_get_option("performance_warnings")
1533+
and sum(not block.is_extension for block in self.blocks) > 100
1534+
):
15301535
warnings.warn(
15311536
"DataFrame is highly fragmented. This is usually the result "
15321537
"of calling `frame.insert` many times, which has poor performance. "

pandas/core/reshape/reshape.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import numpy as np
1212

13+
from pandas._config.config import _get_option
14+
1315
import pandas._libs.reshape as libreshape
1416
from pandas.errors import PerformanceWarning
1517
from pandas.util._decorators import cache_readonly
@@ -144,7 +146,7 @@ def __init__(
144146
num_cells = num_rows * num_columns
145147

146148
# GH 26314: Previous ValueError raised was too restrictive for many users.
147-
if num_cells > np.iinfo(np.int32).max:
149+
if _get_option("performance_warnings") and num_cells > np.iinfo(np.int32).max:
148150
warnings.warn(
149151
f"The following operation may generate {num_cells} cells "
150152
f"in the resulting pandas object.",

pandas/io/pytables.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
get_option,
3333
using_pyarrow_string_dtype,
3434
)
35+
from pandas._config.config import _get_option
3536

3637
from pandas._libs import (
3738
lib,
@@ -3143,7 +3144,7 @@ def write_array(
31433144
pass
31443145
elif inferred_type == "string":
31453146
pass
3146-
else:
3147+
elif _get_option("performance_warnings"):
31473148
ws = performance_doc % (inferred_type, key, items)
31483149
warnings.warn(ws, PerformanceWarning, stacklevel=find_stack_level())
31493150

0 commit comments

Comments
 (0)