From 6f4280d688f4e66ff3f896e300a3e189ed9988bf Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sun, 7 Aug 2022 11:42:57 +0200 Subject: [PATCH 01/18] use find_stack_level everywhere --- .pre-commit-config.yaml | 3 +++ .../development/contributing_codebase.rst | 7 ++++++- pandas/__init__.py | 12 +++++++----- pandas/_libs/interval.pyx | 2 +- pandas/_libs/parsers.pyx | 6 ++++-- pandas/_libs/tslib.pyx | 3 ++- pandas/_libs/tslibs/conversion.pyx | 4 +++- pandas/_libs/tslibs/nattype.pyx | 6 ++++-- pandas/_libs/tslibs/offsets.pyx | 10 ++++++---- pandas/_libs/tslibs/parsing.pyx | 6 ++++-- pandas/_libs/tslibs/period.pyx | 4 +++- pandas/_libs/tslibs/timedeltas.pyx | 10 ++++++---- pandas/_libs/tslibs/timestamps.pyx | 19 ++++++++++--------- pandas/_testing/_warnings.py | 4 +--- pandas/compat/pickle_compat.py | 5 +++-- pandas/core/arrays/categorical.py | 2 +- pandas/core/generic.py | 2 +- pandas/core/indexes/base.py | 2 +- pandas/tseries/frequencies.py | 2 +- scripts/list_future_warnings.sh | 2 +- 20 files changed, 68 insertions(+), 43 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dbddba57ef21c..caeadf28728bf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -146,6 +146,9 @@ repos: # Check for deprecated messages without sphinx directive |(DEPRECATED|DEPRECATE|Deprecated)(:|,|\.) + + # Check for ``stacklevel=5`` instead of ``stacklevel=find_stack_level()`` + |stacklevel=\d+ types_or: [python, cython, rst] - id: cython-casting name: Check Cython casting is `obj`, not ` obj` diff --git a/doc/source/development/contributing_codebase.rst b/doc/source/development/contributing_codebase.rst index c74c44fb1d5f0..0a7623ccf2ca8 100644 --- a/doc/source/development/contributing_codebase.rst +++ b/doc/source/development/contributing_codebase.rst @@ -122,6 +122,7 @@ Otherwise, you need to do it manually: .. code-block:: python import warnings + from pandas.util._exceptions import find_stack_level def old_func(): @@ -130,7 +131,11 @@ Otherwise, you need to do it manually: .. deprecated:: 1.1.0 Use new_func instead. """ - warnings.warn('Use new_func instead.', FutureWarning, stacklevel=2) + warnings.warn( + 'Use new_func instead.', + FutureWarning, + stacklevel=find_stack_level(), + ) new_func() diff --git a/pandas/__init__.py b/pandas/__init__.py index eb5ce71141f46..8070e97f9e4ab 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pandas.util._exceptions import find_stack_level + __docformat__ = "restructuredtext" # Let users know if they're missing any of our hard dependencies @@ -202,7 +204,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.Index with the appropriate dtype instead.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) from pandas.core.api import Float64Index, Int64Index, UInt64Index @@ -217,7 +219,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import from datetime module instead.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) from datetime import datetime as dt @@ -231,7 +233,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import numpy directly instead.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) import numpy as np @@ -242,7 +244,7 @@ def __getattr__(name): f"The {name} class is removed from pandas. Accessing it from " "the top-level namespace will also be removed in the next version.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) return type(name, (), {}) @@ -254,7 +256,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.arrays.SparseArray instead.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) from pandas.core.arrays.sparse import SparseArray as _SparseArray diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index ec1dbff6903e7..ee036b25b5ad4 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -228,7 +228,7 @@ def _warning_interval(inclusive: str | None = None, closed: None | lib.NoDefault warnings.warn( "Argument `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) if closed is None: inclusive = "right" diff --git a/pandas/_libs/parsers.pyx b/pandas/_libs/parsers.pyx index b07fa143c98b6..28029fd50837c 100644 --- a/pandas/_libs/parsers.pyx +++ b/pandas/_libs/parsers.pyx @@ -12,6 +12,8 @@ import sys import time import warnings +from pandas.util._exceptions import find_stack_level + cimport cython from cpython.bytes cimport ( PyBytes_AsString, @@ -958,7 +960,7 @@ cdef class TextReader: "Defining usecols with out of bounds indices is deprecated " "and will raise a ParserError in a future version.", FutureWarning, - stacklevel=6, + stacklevel=find_stack_level(), ) results = {} @@ -1009,7 +1011,7 @@ cdef class TextReader: warnings.warn((f"Both a converter and dtype were specified " f"for column {name} - only the converter will " f"be used."), ParserWarning, - stacklevel=5) + stacklevel=find_stack_level()) results[i] = _apply_converter(conv, self.parser, i, start, end) continue diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index b3e51191e8efa..d1a2dd19761d1 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -8,6 +8,7 @@ from cpython.datetime cimport ( import_datetime, tzinfo, ) +from pandas.util._exceptions import find_stack_level # import datetime C API import_datetime() @@ -843,7 +844,7 @@ cdef inline bint _parse_today_now(str val, int64_t* iresult, bint utc): "deprecated. In a future version, this will match Timestamp('now') " "and Timestamp.now()", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return True diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 0dfb859a3444f..519bc656488c0 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -4,6 +4,8 @@ import warnings import numpy as np +from pandas.util._exceptions import find_stack_level + cimport numpy as cnp from cpython.object cimport PyObject from numpy cimport ( @@ -287,7 +289,7 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit, "Conversion of non-round float with unit={unit} is ambiguous " "and will raise in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) ts = cast_from_unit(ts, unit) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index b05b0ba636251..edf605318691f 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -1,5 +1,7 @@ import warnings +from pandas.util._exceptions import find_stack_level + from cpython.datetime cimport ( PyDate_Check, PyDateTime_Check, @@ -135,7 +137,7 @@ cdef class _NaT(datetime): "order to match the standard library behavior. " "In a future version these will be considered non-comparable.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return False @@ -379,7 +381,7 @@ class NaTType(_NaT): warnings.warn( "NaT.freq is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return None diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index e7c3a709bb251..02a4d1ffefd9e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3,6 +3,8 @@ import re import time import warnings +from pandas.util._exceptions import find_stack_level + cimport cython from cpython.datetime cimport ( PyDate_Check, @@ -469,7 +471,7 @@ cdef class BaseOffset: "DateOffset.__call__ is deprecated and will be removed in a future " "version. Use `offset + other` instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self._apply(other) @@ -479,7 +481,7 @@ cdef class BaseOffset: f"{type(self).__name__}.apply is deprecated and will be removed " "in a future version. Use `offset + other` instead", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) return self._apply(other) @@ -730,7 +732,7 @@ cdef class BaseOffset: warnings.warn( "onOffset is a deprecated, use is_on_offset instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self.is_on_offset(dt) @@ -738,7 +740,7 @@ cdef class BaseOffset: warnings.warn( "isAnchored is a deprecated, use is_anchored instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self.is_anchored() diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index 97a8f81094a8f..10df06958e87c 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -5,6 +5,8 @@ import re import time import warnings +from pandas.util._exceptions import find_stack_level + cimport cython from cpython.datetime cimport ( datetime, @@ -214,7 +216,7 @@ cdef inline object _parse_delimited_date(str date_string, bint dayfirst): format='MM/DD/YYYY', dayfirst='True', ), - stacklevel=4, + stacklevel=find_stack_level(), ) elif not dayfirst and swapped_day_and_month: warnings.warn( @@ -222,7 +224,7 @@ cdef inline object _parse_delimited_date(str date_string, bint dayfirst): format='DD/MM/YYYY', dayfirst='False (the default)', ), - stacklevel=4, + stacklevel=find_stack_level(), ) # In Python <= 3.6.0 there is no range checking for invalid dates # in C api, thus we call faster C version for 3.6.1 or newer diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index fa264f29aa8a8..a9d607ca9fd30 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,5 +1,7 @@ import warnings +from pandas.util._exceptions import find_stack_level + cimport numpy as cnp from cpython.object cimport ( Py_EQ, @@ -1827,7 +1829,7 @@ cdef class _Period(PeriodMixin): "be removed in a future version. Use " "`per.to_timestamp(...).tz_localize(tz)` instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) how = validate_end_alias(how) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 215d1c9d6c722..01395e27270ac 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,6 +1,8 @@ import collections import warnings +from pandas.util._exceptions import find_stack_level + cimport cython from cpython.object cimport ( Py_EQ, @@ -683,7 +685,7 @@ cdef inline timedelta_from_spec(object number, object frac, object unit): "Units 'M', 'Y' and 'y' do not represent unambiguous " "timedelta values and will be removed in a future version.", FutureWarning, - stacklevel=3, + stacklevel=find_stack_level(), ) if unit == 'M': @@ -1055,7 +1057,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.freq is deprecated and will be removed in a future version", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return None @@ -1065,7 +1067,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.is_populated is deprecated and will be removed in a future version", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self._is_populated @@ -1269,7 +1271,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.delta is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self.value diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 66d848ba43da9..9cee16d57e502 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -47,6 +47,7 @@ import_datetime() from pandas._libs.tslibs cimport ccalendar from pandas._libs.tslibs.base cimport ABCTimestamp +from pandas.util._exceptions import find_stack_level from pandas._libs.tslibs.conversion cimport ( _TSObject, convert_datetime_to_tsobject, @@ -253,7 +254,7 @@ cdef class _Timestamp(ABCTimestamp): warnings.warn( "Timestamp.freq is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self._freq @@ -365,7 +366,7 @@ cdef class _Timestamp(ABCTimestamp): "In a future version these will be considered non-comparable. " "Use 'ts == pd.Timestamp(date)' or 'ts.date() == date' instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return NotImplemented else: @@ -666,7 +667,7 @@ cdef class _Timestamp(ABCTimestamp): "version. When you have a freq, use " f"freq.{field}(timestamp) instead.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) @property @@ -1172,7 +1173,7 @@ cdef class _Timestamp(ABCTimestamp): """ if self.nanosecond != 0 and warn: warnings.warn("Discarding nonzero nanoseconds in conversion.", - UserWarning, stacklevel=2) + UserWarning, stacklevel=find_stack_level()) return datetime(self.year, self.month, self.day, self.hour, self.minute, self.second, @@ -1259,7 +1260,7 @@ cdef class _Timestamp(ABCTimestamp): "In a future version, calling 'Timestamp.to_period()' without " "passing a 'freq' will raise an exception.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) return Period(self, freq=freq) @@ -1451,7 +1452,7 @@ class Timestamp(_Timestamp): "Timestamp.utcfromtimestamp(ts).tz_localize(None). " "To get the future behavior, use Timestamp.fromtimestamp(ts, 'UTC')", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return cls(datetime.utcfromtimestamp(ts)) @@ -1687,7 +1688,7 @@ class Timestamp(_Timestamp): "as a wall time, not a UTC time. To interpret as a UTC time, " "use `Timestamp(dt64).tz_localize('UTC').tz_convert(tz)`", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) # Once this deprecation is enforced, we can do # return Timestamp(ts_input).tz_localize(tzobj) @@ -1704,7 +1705,7 @@ class Timestamp(_Timestamp): "The 'freq' argument in Timestamp is deprecated and will be " "removed in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) if not is_offset_object(freq): freq = to_offset(freq) @@ -2040,7 +2041,7 @@ timedelta}, default 'raise' warnings.warn( "Timestamp.freqstr is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=1, + stacklevel=find_stack_level(), ) return self._freqstr diff --git a/pandas/_testing/_warnings.py b/pandas/_testing/_warnings.py index e9df85eae550a..a5b0d1e199863 100644 --- a/pandas/_testing/_warnings.py +++ b/pandas/_testing/_warnings.py @@ -130,9 +130,7 @@ def _assert_caught_expected_warning( if issubclass(actual_warning.category, expected_warning): saw_warning = True - if check_stacklevel and issubclass( - actual_warning.category, (FutureWarning, DeprecationWarning) - ): + if check_stacklevel: _assert_raised_with_correct_stacklevel(actual_warning) if match is not None: diff --git a/pandas/compat/pickle_compat.py b/pandas/compat/pickle_compat.py index c8db82500d0d6..aa5d0cfd4e3eb 100644 --- a/pandas/compat/pickle_compat.py +++ b/pandas/compat/pickle_compat.py @@ -17,6 +17,7 @@ from pandas._libs.arrays import NDArrayBacked from pandas._libs.tslibs import BaseOffset +from pandas.util._exceptions import find_stack_level from pandas import Index from pandas.core.arrays import ( @@ -87,7 +88,7 @@ def __new__(cls) -> Series: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseSeries", new="Series"), FutureWarning, - stacklevel=6, + stacklevel=find_stack_level(), ) return Series(dtype=object) @@ -105,7 +106,7 @@ def __new__(cls) -> DataFrame: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseDataFrame", new="DataFrame"), FutureWarning, - stacklevel=6, + stacklevel=find_stack_level(), ) return DataFrame() diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 127814dc58f4c..234af0eb0d803 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -1010,7 +1010,7 @@ def set_categories( "a future version. Removing unused categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) else: inplace = False diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 003fe2571401f..8122031dbe26b 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2039,7 +2039,7 @@ def __array_wrap__( "The __array_wrap__ method of DataFrame and Series will be removed in " "a future version", DeprecationWarning, - stacklevel=2, + stacklevel=find_stack_level(), ) res = lib.item_from_zerodim(result) if is_scalar(res): diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 14f9b71c5e03c..e8cb412b12f59 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -7436,7 +7436,7 @@ def _maybe_cast_data_without_dtype( "In a future version, the Index constructor will not infer numeric " "dtypes when passed object-dtype sequences (matching Series behavior)", FutureWarning, - stacklevel=3, + stacklevel=find_stack_level(), ) result = ensure_wrapped_if_datetimelike(result) return result diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index b2fbc022b2708..9f553686ca829 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -234,7 +234,7 @@ def __init__(self, index, warn: bool = True) -> None: "warn is deprecated (and never implemented) and " "will be removed in a future version.", FutureWarning, - stacklevel=3, + stacklevel=find_stack_level(), ) self.warn = warn diff --git a/scripts/list_future_warnings.sh b/scripts/list_future_warnings.sh index 121f4f5a92abb..a75aea905a4c8 100755 --- a/scripts/list_future_warnings.sh +++ b/scripts/list_future_warnings.sh @@ -6,7 +6,7 @@ # This is useful to detect features that have been deprecated, and should be # removed from the code. For example, if a line of code contains: # -# warning.warn('Method deprecated', FutureWarning, stacklevel=2) +# warning.warn('Method deprecated', FutureWarning, stacklevel=find_stack_level()) # # Which is released in Pandas 0.20.0, then it is expected that the method # is removed before releasing Pandas 0.24.0, including the warning. If it From 781fe674314d75df10683241887c6212374b2424 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sun, 7 Aug 2022 15:12:56 +0200 Subject: [PATCH 02/18] fixup --- pandas/_config/config.py | 5 ++-- pandas/core/algorithms.py | 2 +- pandas/core/arrays/datetimelike.py | 1 + pandas/core/arrays/datetimes.py | 2 ++ pandas/core/arrays/sparse/array.py | 2 +- pandas/core/computation/expressions.py | 4 ++- pandas/core/reshape/merge.py | 2 ++ pandas/core/reshape/reshape.py | 2 ++ pandas/io/clipboard/__init__.py | 13 +++++++--- pandas/io/clipboards.py | 13 +++++++--- pandas/io/common.py | 1 + pandas/io/formats/css.py | 18 ++++++++++--- pandas/io/formats/excel.py | 7 +++++- pandas/io/json/_table_schema.py | 9 +++++-- pandas/io/pytables.py | 6 ++++- pandas/io/sas/sas_xport.py | 6 ++++- pandas/io/sql.py | 7 +++++- pandas/io/stata.py | 35 +++++++++++++++++++++----- pandas/plotting/_matplotlib/boxplot.py | 5 +++- pandas/plotting/_matplotlib/core.py | 4 ++- pandas/plotting/_matplotlib/style.py | 5 +++- pandas/plotting/_matplotlib/tools.py | 1 + 22 files changed, 121 insertions(+), 29 deletions(-) diff --git a/pandas/_config/config.py b/pandas/_config/config.py index d5e77d824340d..4ee42256e9a1a 100644 --- a/pandas/_config/config.py +++ b/pandas/_config/config.py @@ -70,6 +70,7 @@ F, T, ) +from pandas.util._exceptions import find_stack_level class DeprecatedOption(NamedTuple): @@ -657,7 +658,7 @@ def _warn_if_deprecated(key: str) -> bool: d = _get_deprecated_option(key) if d: if d.msg: - warnings.warn(d.msg, FutureWarning) + warnings.warn(d.msg, FutureWarning, stacklevel=find_stack_level()) else: msg = f"'{key}' is deprecated" if d.removal_ver: @@ -667,7 +668,7 @@ def _warn_if_deprecated(key: str) -> bool: else: msg += ", please refrain from using it." - warnings.warn(msg, FutureWarning) + warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) return True return False diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index 159c0bb2e72c0..9cbe6b41a255e 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -1034,7 +1034,7 @@ def mode( try: npresult = np.sort(npresult) except TypeError as err: - warnings.warn(f"Unable to sort modes: {err}") + warnings.warn(f"Unable to sort modes: {err}", stacklevel=find_stack_level()) result = _reconstruct_data(npresult, original.dtype, original) return result diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 11c236836e791..471ecc5950dd9 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -1372,6 +1372,7 @@ def _addsub_object_array(self, other: np.ndarray, op): "Adding/subtracting object-dtype array to " f"{type(self).__name__} not vectorized.", PerformanceWarning, + stacklevel=find_stack_level(), ) # Caller is responsible for broadcasting if necessary diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index ffd093b86582c..5a3abe851fb7b 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -701,6 +701,7 @@ def _add_offset(self, offset) -> DatetimeArray: warnings.warn( "Non-vectorized DateOffset being applied to Series or DatetimeIndex.", PerformanceWarning, + stacklevel=find_stack_level(), ) result = self.astype("O") + offset result = type(self)._from_sequence(result) @@ -1098,6 +1099,7 @@ def to_period(self, freq=None) -> PeriodArray: "Converting to PeriodArray/Index representation " "will drop timezone information.", UserWarning, + stacklevel=find_stack_level(), ) if freq is None: diff --git a/pandas/core/arrays/sparse/array.py b/pandas/core/arrays/sparse/array.py index f946f881311c1..b1025038c9592 100644 --- a/pandas/core/arrays/sparse/array.py +++ b/pandas/core/arrays/sparse/array.py @@ -777,7 +777,7 @@ def fillna( elif method is not None: msg = "fillna with 'method' requires high memory usage." - warnings.warn(msg, PerformanceWarning) + warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level()) new_values = np.asarray(self) # interpolate_2d modifies new_values inplace interpolate_2d(new_values, method=method, limit=limit) diff --git a/pandas/core/computation/expressions.py b/pandas/core/computation/expressions.py index e82bec47c6ac5..afb4d0d549c45 100644 --- a/pandas/core/computation/expressions.py +++ b/pandas/core/computation/expressions.py @@ -15,6 +15,7 @@ from pandas._config import get_option from pandas._typing import FuncType +from pandas.util._exceptions import find_stack_level from pandas.core.computation.check import NUMEXPR_INSTALLED from pandas.core.ops import roperator @@ -214,7 +215,8 @@ def _bool_arith_fallback(op_str, a, b): warnings.warn( f"evaluating in Python space because the {repr(op_str)} " "operator is not supported by numexpr for the bool dtype, " - f"use {repr(_BOOL_OP_UNSUPPORTED[op_str])} instead." + f"use {repr(_BOOL_OP_UNSUPPORTED[op_str])} instead.", + stacklevel=find_stack_level(), ) return True return False diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index 77a0d34132da0..c7744945ad4af 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -1208,6 +1208,7 @@ def _maybe_coerce_merge_keys(self) -> None: "columns where the float values " "are not equal to their int representation.", UserWarning, + stacklevel=find_stack_level(), ) continue @@ -1220,6 +1221,7 @@ def _maybe_coerce_merge_keys(self) -> None: "columns where the float values " "are not equal to their int representation.", UserWarning, + stacklevel=find_stack_level(), ) continue diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py index 5039a29b74f1b..82e4a91f5e935 100644 --- a/pandas/core/reshape/reshape.py +++ b/pandas/core/reshape/reshape.py @@ -10,6 +10,7 @@ from pandas._typing import npt from pandas.errors import PerformanceWarning from pandas.util._decorators import cache_readonly +from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.cast import maybe_promote from pandas.core.dtypes.common import ( @@ -127,6 +128,7 @@ def __init__(self, index: MultiIndex, level=-1, constructor=None) -> None: f"The following operation may generate {num_cells} cells " f"in the resulting pandas object.", PerformanceWarning, + stacklevel=find_stack_level(), ) self._make_selectors() diff --git a/pandas/io/clipboard/__init__.py b/pandas/io/clipboard/__init__.py index 27fb06dfb6023..28751fd531ffb 100644 --- a/pandas/io/clipboard/__init__.py +++ b/pandas/io/clipboard/__init__.py @@ -42,6 +42,7 @@ """ __version__ = "1.7.0" + import contextlib import ctypes from ctypes import ( @@ -62,6 +63,7 @@ PyperclipException, PyperclipWindowsException, ) +from pandas.util._exceptions import find_stack_level # `import PyQt4` sys.exit()s if DISPLAY is not in the environment. # Thus, we need to detect the presence of $DISPLAY manually @@ -270,10 +272,14 @@ def copy_dev_clipboard(text): if text == "": warnings.warn( "Pyperclip cannot copy a blank string to the clipboard on Cygwin. " - "This is effectively a no-op." + "This is effectively a no-op.", + stacklevel=find_stack_level(), ) if "\r" in text: - warnings.warn("Pyperclip cannot handle \\r characters on Cygwin.") + warnings.warn( + "Pyperclip cannot handle \\r characters on Cygwin.", + stacklevel=find_stack_level(), + ) with open("/dev/clipboard", "wt") as fd: fd.write(text) @@ -517,7 +523,8 @@ def determine_clipboard(): if os.path.exists("/dev/clipboard"): warnings.warn( "Pyperclip's support for Cygwin is not perfect, " - "see https://github.com/asweigart/pyperclip/issues/55" + "see https://github.com/asweigart/pyperclip/issues/55", + stacklevel=find_stack_level(), ) return init_dev_clipboard_clipboard() diff --git a/pandas/io/clipboards.py b/pandas/io/clipboards.py index 0968f1facf128..a3e778e552439 100644 --- a/pandas/io/clipboards.py +++ b/pandas/io/clipboards.py @@ -4,6 +4,8 @@ from io import StringIO import warnings +from pandas.util._exceptions import find_stack_level + from pandas.core.dtypes.generic import ABCDataFrame from pandas import ( @@ -79,7 +81,8 @@ def read_clipboard(sep: str = r"\s+", **kwargs): # pragma: no cover kwargs["engine"] = "python" elif len(sep) > 1 and kwargs.get("engine") == "c": warnings.warn( - "read_clipboard with regex separator does not work properly with c engine." + "read_clipboard with regex separator does not work properly with c engine.", + stacklevel=find_stack_level(), ) return read_csv(StringIO(text), sep=sep, **kwargs) @@ -135,10 +138,14 @@ def to_clipboard( return except TypeError: warnings.warn( - "to_clipboard in excel mode requires a single character separator." + "to_clipboard in excel mode requires a single character separator.", + stacklevel=find_stack_level(), ) elif sep is not None: - warnings.warn("to_clipboard with excel=False ignores the sep argument.") + warnings.warn( + "to_clipboard with excel=False ignores the sep argument.", + stacklevel=find_stack_level(), + ) if isinstance(obj, ABCDataFrame): # str(df) has various unhelpful defaults, like truncation diff --git a/pandas/io/common.py b/pandas/io/common.py index d911499aa848e..f31de63aa42a7 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -338,6 +338,7 @@ def _get_filepath_or_buffer( warnings.warn( f"{compression} will not write the byte order mark for {encoding}", UnicodeWarning, + stacklevel=find_stack_level(), ) # Use binary mode when converting path-like objects to file-like objects (fsspec) diff --git a/pandas/io/formats/css.py b/pandas/io/formats/css.py index 778df087d28d8..cfc95bc9d9569 100644 --- a/pandas/io/formats/css.py +++ b/pandas/io/formats/css.py @@ -13,6 +13,7 @@ import warnings from pandas.errors import CSSWarning +from pandas.util._exceptions import find_stack_level def _side_expander(prop_fmt: str) -> Callable: @@ -46,7 +47,11 @@ def expand(self, prop, value: str) -> Generator[tuple[str, str], None, None]: try: mapping = self.SIDE_SHORTHANDS[len(tokens)] except KeyError: - warnings.warn(f'Could not expand "{prop}: {value}"', CSSWarning) + warnings.warn( + f'Could not expand "{prop}: {value}"', + CSSWarning, + stacklevel=find_stack_level(), + ) return for key, idx in zip(self.SIDES, mapping): yield prop_fmt.format(key), tokens[idx] @@ -88,7 +93,9 @@ def expand(self, prop, value: str) -> Generator[tuple[str, str], None, None]: tokens = value.split() if len(tokens) == 0 or len(tokens) > 3: warnings.warn( - f'Too many tokens provided to "{prop}" (expected 1-3)', CSSWarning + f'Too many tokens provided to "{prop}" (expected 1-3)', + CSSWarning, + stacklevel=find_stack_level(), ) # TODO: Can we use current color as initial value to comply with CSS standards? @@ -324,7 +331,11 @@ def _update_other_units(self, props: dict[str, str]) -> dict[str, str]: def size_to_pt(self, in_val, em_pt=None, conversions=UNIT_RATIOS): def _error(): - warnings.warn(f"Unhandled size: {repr(in_val)}", CSSWarning) + warnings.warn( + f"Unhandled size: {repr(in_val)}", + CSSWarning, + stacklevel=find_stack_level(), + ) return self.size_to_pt("1!!default", conversions=conversions) match = re.match(r"^(\S*?)([a-zA-Z%!].*)", in_val) @@ -396,4 +407,5 @@ def parse(self, declarations_str: str) -> Iterator[tuple[str, str]]: warnings.warn( f"Ill-formatted attribute: expected a colon in {repr(decl)}", CSSWarning, + stacklevel=find_stack_level(), ) diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py index 5a7d0a4690bbd..ce7f663dd5703 100644 --- a/pandas/io/formats/excel.py +++ b/pandas/io/formats/excel.py @@ -28,6 +28,7 @@ StorageOptions, ) from pandas.util._decorators import doc +from pandas.util._exceptions import find_stack_level from pandas.core.dtypes import missing from pandas.core.dtypes.common import ( @@ -427,7 +428,11 @@ def color_to_excel(self, val: str | None) -> str | None: try: return self.NAMED_COLORS[val] except KeyError: - warnings.warn(f"Unhandled color format: {repr(val)}", CSSWarning) + warnings.warn( + f"Unhandled color format: {repr(val)}", + CSSWarning, + stacklevel=find_stack_level(), + ) return None def _is_hex_color(self, color_string: str) -> bool: diff --git a/pandas/io/json/_table_schema.py b/pandas/io/json/_table_schema.py index b7a8b5cc82f7a..0d6cab20f2a59 100644 --- a/pandas/io/json/_table_schema.py +++ b/pandas/io/json/_table_schema.py @@ -17,6 +17,7 @@ DtypeObj, JSONSerializable, ) +from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.base import _registry as registry from pandas.core.dtypes.common import ( @@ -100,10 +101,14 @@ def set_default_names(data): if com.all_not_none(*data.index.names): nms = data.index.names if len(nms) == 1 and data.index.name == "index": - warnings.warn("Index name of 'index' is not round-trippable.") + warnings.warn( + "Index name of 'index' is not round-trippable.", + stacklevel=find_stack_level(), + ) elif len(nms) > 1 and any(x.startswith("level_") for x in nms): warnings.warn( - "Index names beginning with 'level_' are not round-trippable." + "Index names beginning with 'level_' are not round-trippable.", + stacklevel=find_stack_level(), ) return data diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index a4049eff8ae71..855d97733ca06 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -3538,7 +3538,11 @@ def validate_version(self, where=None) -> None: if where is not None: if self.is_old_version: ws = incompatibility_doc % ".".join([str(x) for x in self.version]) - warnings.warn(ws, IncompatibilityWarning) + warnings.warn( + ws, + IncompatibilityWarning, + stacklevel=find_stack_level(), + ) def validate_min_itemsize(self, min_itemsize) -> None: """ diff --git a/pandas/io/sas/sas_xport.py b/pandas/io/sas/sas_xport.py index a2e217767d1d4..c188e8d1b03c3 100644 --- a/pandas/io/sas/sas_xport.py +++ b/pandas/io/sas/sas_xport.py @@ -23,6 +23,7 @@ ReadBuffer, ) from pandas.util._decorators import Appender +from pandas.util._exceptions import find_stack_level import pandas as pd @@ -412,7 +413,10 @@ def _record_count(self) -> int: total_records_length = self.filepath_or_buffer.tell() - self.record_start if total_records_length % 80 != 0: - warnings.warn("xport file may be corrupted.") + warnings.warn( + "xport file may be corrupted.", + stacklevel=find_stack_level(), + ) if self.record_length > 80: self.filepath_or_buffer.seek(self.record_start) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 71fecba4340ac..82a20c080c1d3 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -761,6 +761,7 @@ def pandasSQL_builder(con, schema: str | None = None) -> SQLDatabase | SQLiteDat "database string URI or sqlite3 DBAPI2 connection. " "Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.", UserWarning, + stacklevel=find_stack_level(), ) return SQLiteDatabase(con) @@ -1654,7 +1655,11 @@ def check_case_sensitive( "due to case sensitivity issues. Consider using lower " "case table names." ) - warnings.warn(msg, UserWarning) + warnings.warn( + msg, + UserWarning, + stacklevel=find_stack_level(), + ) def to_sql( self, diff --git a/pandas/io/stata.py b/pandas/io/stata.py index e59b6c8770389..201b6500c22b7 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -51,6 +51,7 @@ Appender, doc, ) +from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.common import ( ensure_object, @@ -348,7 +349,10 @@ def convert_delta_safe(base, deltas, unit) -> Series: conv_dates = convert_delta_safe(base, ms, "ms") elif fmt.startswith(("%tC", "tC")): - warnings.warn("Encountered %tC format. Leaving in Stata Internal Format.") + warnings.warn( + "Encountered %tC format. Leaving in Stata Internal Format.", + stacklevel=find_stack_level(), + ) conv_dates = Series(dates, dtype=object) if has_bad_values: conv_dates[bad_locs] = NaT @@ -462,7 +466,10 @@ def g(x: datetime.datetime) -> int: d = parse_dates_safe(dates, delta=True) conv_dates = d.delta / 1000 elif fmt in ["%tC", "tC"]: - warnings.warn("Stata Internal Format tC not supported.") + warnings.warn( + "Stata Internal Format tC not supported.", + stacklevel=find_stack_level(), + ) conv_dates = dates elif fmt in ["%td", "td"]: d = parse_dates_safe(dates, delta=True) @@ -642,7 +649,11 @@ def _cast_to_stata_types(data: DataFrame) -> DataFrame: sentinel = StataMissingValue.BASE_MISSING_VALUES[data[col].dtype.name] data.loc[orig_missing, col] = sentinel if ws: - warnings.warn(ws, PossiblePrecisionLoss) + warnings.warn( + ws, + PossiblePrecisionLoss, + stacklevel=find_stack_level(), + ) return data @@ -697,6 +708,7 @@ def _prepare_value_labels(self): warnings.warn( value_label_mismatch_doc.format(self.labname), ValueLabelTypeMismatch, + stacklevel=find_stack_level(), ) category = category.encode(self._encoding) offsets.append(self.text_len) @@ -1506,7 +1518,11 @@ def _decode(self, s: bytes) -> str: so the fallback encoding of latin-1 is being used. This can happen when a file has been incorrectly encoded by Stata or some other software. You should verify the string values returned are correct.""" - warnings.warn(msg, UnicodeWarning) + warnings.warn( + msg, + UnicodeWarning, + stacklevel=find_stack_level(), + ) return s.decode("latin-1") def _read_value_labels(self) -> None: @@ -1902,7 +1918,9 @@ def _do_convert_categoricals( if self._using_iterator: # warn is using an iterator warnings.warn( - categorical_conversion_warning, CategoricalConversionWarning + categorical_conversion_warning, + CategoricalConversionWarning, + stacklevel=find_stack_level(), ) initial_categories = None cat_data = Categorical( @@ -2482,7 +2500,11 @@ def _check_column_names(self, data: DataFrame) -> DataFrame: conversion_warning.append(msg) ws = invalid_name_doc.format("\n ".join(conversion_warning)) - warnings.warn(ws, InvalidColumnName) + warnings.warn( + ws, + InvalidColumnName, + stacklevel=find_stack_level(), + ) self._converted_names = converted_names self._update_strl_names() @@ -2649,6 +2671,7 @@ def write_file(self) -> None: f"This save was not successful but {self._fname} could not " "be deleted. This file is not valid.", ResourceWarning, + stacklevel=find_stack_level(), ) raise exc diff --git a/pandas/plotting/_matplotlib/boxplot.py b/pandas/plotting/_matplotlib/boxplot.py index 045c27bb8fe56..6789485f2b9eb 100644 --- a/pandas/plotting/_matplotlib/boxplot.py +++ b/pandas/plotting/_matplotlib/boxplot.py @@ -10,6 +10,8 @@ from matplotlib.artist import setp import numpy as np +from pandas.util._exceptions import find_stack_level + from pandas.core.dtypes.common import is_dict_like from pandas.core.dtypes.missing import remove_na_arraylike @@ -89,7 +91,8 @@ def _validate_color_args(self): if self.colormap is not None: warnings.warn( "'color' and 'colormap' cannot be used " - "simultaneously. Using 'color'" + "simultaneously. Using 'color'", + stacklevel=find_stack_level(), ) self.color = self.kwds.pop("color") diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index ee7493813f13a..1909a8168ddd0 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -22,6 +22,7 @@ ) from pandas.errors import AbstractMethodError from pandas.util._decorators import cache_readonly +from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.common import ( is_categorical_dtype, @@ -394,7 +395,8 @@ def _validate_color_args(self): "color" in self.kwds or "colors" in self.kwds ) and self.colormap is not None: warnings.warn( - "'color' and 'colormap' cannot be used simultaneously. Using 'color'" + "'color' and 'colormap' cannot be used simultaneously. Using 'color'", + stacklevel=find_stack_level(), ) if "color" in self.kwds and self.style is not None: diff --git a/pandas/plotting/_matplotlib/style.py b/pandas/plotting/_matplotlib/style.py index 9e459b82fec97..f7668f7b8ff29 100644 --- a/pandas/plotting/_matplotlib/style.py +++ b/pandas/plotting/_matplotlib/style.py @@ -15,6 +15,8 @@ import matplotlib.colors import numpy as np +from pandas.util._exceptions import find_stack_level + from pandas.core.dtypes.common import is_list_like import pandas.core.common as com @@ -121,7 +123,8 @@ def _derive_colors( elif color is not None: if colormap is not None: warnings.warn( - "'color' and 'colormap' cannot be used simultaneously. Using 'color'" + "'color' and 'colormap' cannot be used simultaneously. Using 'color'", + stacklevel=find_stack_level(), ) return _get_colors_from_color(color) else: diff --git a/pandas/plotting/_matplotlib/tools.py b/pandas/plotting/_matplotlib/tools.py index a8b1e4c572c43..1925dd8c4023c 100644 --- a/pandas/plotting/_matplotlib/tools.py +++ b/pandas/plotting/_matplotlib/tools.py @@ -233,6 +233,7 @@ def create_subplots( warnings.warn( "When passing multiple axes, layout keyword is ignored.", UserWarning, + stacklevel=find_stack_level(), ) if sharex or sharey: warnings.warn( From 503f4bc954f6975e1b9d73b3a537696a173e0ab0 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sun, 7 Aug 2022 15:57:18 +0200 Subject: [PATCH 03/18] pyx fixups --- pandas/_libs/lib.pyx | 2 ++ pandas/_libs/tslibs/timestamps.pyx | 1 + 2 files changed, 3 insertions(+) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index c90c9003c8d60..36f5f832bf607 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -29,6 +29,7 @@ from cython cimport ( Py_ssize_t, floating, ) +from pandas.util._exceptions import find_stack_level import_datetime() @@ -352,6 +353,7 @@ def fast_unique_multiple(list arrays, sort: bool = True): "The values in the array are unorderable. " "Pass `sort=False` to suppress this warning.", RuntimeWarning, + stacklevel=find_stack_level(), ) pass diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 9cee16d57e502..35de6f52445d2 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1252,6 +1252,7 @@ cdef class _Timestamp(ABCTimestamp): warnings.warn( "Converting to Period representation will drop timezone information.", UserWarning, + stacklevel=find_stack_level(), ) if freq is None: From aa57ad2278c8fb5da4a96e78acd7dc73d41ae13c Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 12:00:06 +0200 Subject: [PATCH 04/18] fixup test_optional_dependency --- pandas/compat/_optional.py | 4 +++- scripts/validate_min_versions_in_sync.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/compat/_optional.py b/pandas/compat/_optional.py index ad6c6fb839f10..ef8bce30ecb50 100644 --- a/pandas/compat/_optional.py +++ b/pandas/compat/_optional.py @@ -5,6 +5,8 @@ import types import warnings +from pandas.util._exceptions import find_stack_level + from pandas.util.version import Version # Update install.rst when updating versions! @@ -158,7 +160,7 @@ def import_optional_dependency( f"(version '{version}' currently installed)." ) if errors == "warn": - warnings.warn(msg, UserWarning) + warnings.warn(msg, UserWarning, stacklevel=find_stack_level()) return None elif errors == "raise": raise ImportError(msg) diff --git a/scripts/validate_min_versions_in_sync.py b/scripts/validate_min_versions_in_sync.py index 4dbf6a4cdcef8..b0626d5b6cb55 100755 --- a/scripts/validate_min_versions_in_sync.py +++ b/scripts/validate_min_versions_in_sync.py @@ -25,9 +25,11 @@ # in pre-commit environment sys.path.append("pandas/compat") sys.path.append("pandas/util") +import _exceptions import version sys.modules["pandas.util.version"] = version +sys.modules["pandas.util._exceptions"] = _exceptions import _optional From fe06f187cf7757cb1a7e7fec305d503a949eb2aa Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 12:06:19 +0200 Subject: [PATCH 05/18] fixup api --- pandas/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/__init__.py b/pandas/__init__.py index 8070e97f9e4ab..b8382f783ad6a 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -1,7 +1,5 @@ from __future__ import annotations -from pandas.util._exceptions import find_stack_level - __docformat__ = "restructuredtext" # Let users know if they're missing any of our hard dependencies @@ -199,6 +197,8 @@ def __getattr__(name): import warnings if name in __deprecated_num_index_names: + from pandas.util._exceptions import find_stack_level + warnings.warn( f"pandas.{name} is deprecated " "and will be removed from pandas in a future version. " From b18b22326c7e29ffcc2f3b556d7ac43d41048cee Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 14:48:12 +0200 Subject: [PATCH 06/18] set check_stacklevel=False for some tests --- pandas/tests/apply/test_str.py | 4 +++- pandas/tests/extension/test_sparse.py | 10 +++++----- .../tests/io/parser/common/test_chunksize.py | 8 ++++++-- .../io/parser/common/test_common_basic.py | 11 ++++++++-- .../io/parser/dtypes/test_dtypes_basic.py | 12 +++++++---- pandas/tests/io/parser/test_c_parser_only.py | 20 ++++++++++--------- pandas/tests/io/parser/test_dialect.py | 11 +++++++--- pandas/tests/io/parser/test_parse_dates.py | 12 +++++++---- .../io/parser/test_python_parser_only.py | 10 ++++++++-- pandas/tests/plotting/test_boxplot_method.py | 8 ++++---- pandas/tests/plotting/test_misc.py | 2 +- 11 files changed, 71 insertions(+), 37 deletions(-) diff --git a/pandas/tests/apply/test_str.py b/pandas/tests/apply/test_str.py index 2af063dee8b55..38b2a5459eb1f 100644 --- a/pandas/tests/apply/test_str.py +++ b/pandas/tests/apply/test_str.py @@ -80,7 +80,9 @@ def test_apply_np_transformer(float_frame, op, how): if op in ["log", "sqrt"]: warn = RuntimeWarning - with tm.assert_produces_warning(warn): + with tm.assert_produces_warning(warn, check_stacklevel=False): + # float_frame fixture is defined in conftest.py, so we don't check the + # stacklevel as otherwise the test would fail. result = getattr(float_frame, how)(op) expected = getattr(np, op)(float_frame) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/extension/test_sparse.py b/pandas/tests/extension/test_sparse.py index 60eef0d8097e4..0a2686a24c732 100644 --- a/pandas/tests/extension/test_sparse.py +++ b/pandas/tests/extension/test_sparse.py @@ -246,11 +246,11 @@ def test_isna(self, data_missing): self.assert_equal(sarr.isna(), expected) def test_fillna_limit_pad(self, data_missing): - with tm.assert_produces_warning(PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning, check_stacklevel=False): super().test_fillna_limit_pad(data_missing) def test_fillna_limit_backfill(self, data_missing): - with tm.assert_produces_warning(PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning, check_stacklevel=False): super().test_fillna_limit_backfill(data_missing) def test_fillna_no_op_returns_copy(self, data, request): @@ -258,11 +258,11 @@ def test_fillna_no_op_returns_copy(self, data, request): request.node.add_marker( pytest.mark.xfail(reason="returns array with different fill value") ) - with tm.assert_produces_warning(PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning, check_stacklevel=False): super().test_fillna_no_op_returns_copy(data) def test_fillna_series_method(self, data_missing): - with tm.assert_produces_warning(PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning, check_stacklevel=False): super().test_fillna_limit_backfill(data_missing) @pytest.mark.xfail(reason="Unsupported") @@ -373,7 +373,7 @@ def test_combine_first(self, data, request): super().test_combine_first(data) def test_searchsorted(self, data_for_sorting, as_series): - with tm.assert_produces_warning(PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning, check_stacklevel=False): super().test_searchsorted(data_for_sorting, as_series) def test_shift_0_periods(self, data): diff --git a/pandas/tests/io/parser/common/test_chunksize.py b/pandas/tests/io/parser/common/test_chunksize.py index 8a3f8788a45aa..c8cef56c73902 100644 --- a/pandas/tests/io/parser/common/test_chunksize.py +++ b/pandas/tests/io/parser/common/test_chunksize.py @@ -192,8 +192,12 @@ def test_warn_if_chunks_have_mismatched_type(all_parsers): buf = StringIO(data) - with tm.assert_produces_warning(warning_type): - df = parser.read_csv(buf) + df = parser.read_csv_check_warnings( + warning_type, + r"Columns \(0\) have mixed types. " + "Specify dtype option on import or set low_memory=False.", + buf, + ) assert df.a.dtype == object diff --git a/pandas/tests/io/parser/common/test_common_basic.py b/pandas/tests/io/parser/common/test_common_basic.py index a0da3a7eaadce..a7cdc3c1a84d2 100644 --- a/pandas/tests/io/parser/common/test_common_basic.py +++ b/pandas/tests/io/parser/common/test_common_basic.py @@ -732,8 +732,15 @@ def test_no_header_two_extra_columns(all_parsers): ref = DataFrame([["foo", "bar", "baz"]], columns=column_names) stream = StringIO("foo,bar,baz,bam,blah") parser = all_parsers - with tm.assert_produces_warning(ParserWarning): - df = parser.read_csv(stream, header=None, names=column_names, index_col=False) + df = parser.read_csv_check_warnings( + ParserWarning, + "Length of header or names does not match length of data. " + "This leads to a loss of data with index_col=False.", + stream, + header=None, + names=column_names, + index_col=False, + ) tm.assert_frame_equal(df, ref) diff --git a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py index da53664a0278d..4cb297872c5b6 100644 --- a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py +++ b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py @@ -103,10 +103,14 @@ def test_dtype_with_converters(all_parsers): 1.2,2.3""" # Dtype spec ignored if converted specified. - with tm.assert_produces_warning(ParserWarning): - result = parser.read_csv( - StringIO(data), dtype={"a": "i8"}, converters={"a": lambda x: str(x)} - ) + result = parser.read_csv( + ParserWarning, + "Both a converter and dtype were specified for column a" + "- only the converter will be used.", + StringIO(data), + dtype={"a": "i8"}, + converters={"a": lambda x: str(x)}, + ) expected = DataFrame({"a": ["1.1", "1.2"], "b": [2.2, 2.3]}) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/io/parser/test_c_parser_only.py b/pandas/tests/io/parser/test_c_parser_only.py index 9a81790ca3bb0..ecc49ea8adb9f 100644 --- a/pandas/tests/io/parser/test_c_parser_only.py +++ b/pandas/tests/io/parser/test_c_parser_only.py @@ -59,15 +59,17 @@ def test_buffer_rd_bytes(c_parser_only): ) parser = c_parser_only - with tm.assert_produces_warning(RuntimeWarning): - # compression has no effect when passing a non-binary object as input - for _ in range(100): - try: - parser.read_csv( - StringIO(data), compression="gzip", delim_whitespace=True - ) - except Exception: - pass + for _ in range(100): + try: + parser.read_csv_check_warnings( + RuntimeWarning, + "compression has no effect when passing a non-binary object as input", + StringIO(data), + compression="gzip", + delim_whitespace=True, + ) + except Exception: + pass def test_delim_whitespace_custom_terminator(c_parser_only): diff --git a/pandas/tests/io/parser/test_dialect.py b/pandas/tests/io/parser/test_dialect.py index 55b193903bce0..3956967631ea8 100644 --- a/pandas/tests/io/parser/test_dialect.py +++ b/pandas/tests/io/parser/test_dialect.py @@ -108,9 +108,14 @@ def test_dialect_conflict_except_delimiter(all_parsers, custom_dialect, arg, val kwds[arg] = "blah" with tm.with_csv_dialect(dialect_name, **dialect_kwargs): - with tm.assert_produces_warning(warning_klass): - result = parser.read_csv(StringIO(data), dialect=dialect_name, **kwds) - tm.assert_frame_equal(result, expected) + result = parser.read_csv_check_warnings( + warning_klass, + "Conflicting values for", + StringIO(data), + dialect=dialect_name, + **kwds, + ) + tm.assert_frame_equal(result, expected) @pytest.mark.parametrize( diff --git a/pandas/tests/io/parser/test_parse_dates.py b/pandas/tests/io/parser/test_parse_dates.py index 5d2e5bccd9762..9c8809b6099f9 100644 --- a/pandas/tests/io/parser/test_parse_dates.py +++ b/pandas/tests/io/parser/test_parse_dates.py @@ -1678,10 +1678,14 @@ def test_parse_delimited_date_swap_with_warning( parser = all_parsers expected = DataFrame({0: [expected]}, dtype="datetime64[ns]") warning_msg = "Specify a format to ensure consistent parsing" - with tm.assert_produces_warning(UserWarning, match=warning_msg): - result = parser.read_csv( - StringIO(date_string), header=None, dayfirst=dayfirst, parse_dates=[0] - ) + result = parser.read_csv_check_warnings( + UserWarning, + warning_msg, + StringIO(date_string), + header=None, + dayfirst=dayfirst, + parse_dates=[0], + ) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/io/parser/test_python_parser_only.py b/pandas/tests/io/parser/test_python_parser_only.py index 0717078a83a46..84e0c8cbfdf88 100644 --- a/pandas/tests/io/parser/test_python_parser_only.py +++ b/pandas/tests/io/parser/test_python_parser_only.py @@ -466,8 +466,14 @@ def test_index_col_false_and_header_none(python_parser_only): 0.5,0.03 0.1,0.2,0.3,2 """ - with tm.assert_produces_warning(ParserWarning, match="Length of header"): - result = parser.read_csv(StringIO(data), sep=",", header=None, index_col=False) + result = parser.read_csv_check_warnings( + ParserWarning, + "Length of header", + StringIO(data), + sep=",", + header=None, + index_col=False, + ) expected = DataFrame({0: [0.5, 0.1], 1: [0.03, 0.2]}) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 9ca8a71ed1897..595af94030a85 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -61,16 +61,16 @@ def test_boxplot_legacy1(self): _check_plot_works(df.boxplot, return_type="dict") _check_plot_works(df.boxplot, column=["one", "two"], return_type="dict") # _check_plot_works adds an ax so catch warning. see GH #13188 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.boxplot, column=["one", "two"], by="indic") _check_plot_works(df.boxplot, column="one", by=["indic", "indic2"]) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.boxplot, by="indic") - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.boxplot, by=["indic", "indic2"]) _check_plot_works(plotting._core.boxplot, data=df["one"], return_type="dict") _check_plot_works(df.boxplot, notch=1, return_type="dict") - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.boxplot, by="indic", notch=1) def test_boxplot_legacy2(self): diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index ab8e64be648d4..95900e163ad9e 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -107,7 +107,7 @@ def test_scatter_matrix_axis(self, pass_axis): df = DataFrame(np.random.randn(100, 3)) # we are plotting multiples on a sub-plot - with tm.assert_produces_warning(UserWarning, raise_on_extra_warnings=True): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( scatter_matrix, filterwarnings="always", From ff840811022c768a0fcd2e5faad802988bead56a Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 15:19:52 +0200 Subject: [PATCH 07/18] use lru_cache for currentframe --- .pre-commit-config.yaml | 2 +- .../development/contributing_codebase.rst | 2 +- pandas/__init__.py | 193 +++++++++--------- pandas/_config/config.py | 11 +- pandas/_libs/interval.pyx | 4 +- pandas/_libs/lib.pyx | 2 +- pandas/_libs/parsers.pyx | 4 +- pandas/_libs/tslib.pyx | 2 +- pandas/_libs/tslibs/conversion.pyx | 2 +- pandas/_libs/tslibs/nattype.pyx | 4 +- pandas/_libs/tslibs/offsets.pyx | 8 +- pandas/_libs/tslibs/parsing.pyx | 5 +- pandas/_libs/tslibs/period.pyx | 2 +- pandas/_libs/tslibs/timedeltas.pyx | 8 +- pandas/_libs/tslibs/timestamps.pyx | 20 +- pandas/_testing/asserters.py | 11 +- pandas/compat/_optional.py | 7 +- pandas/compat/pickle_compat.py | 5 +- pandas/core/accessor.py | 3 +- pandas/core/algorithms.py | 11 +- pandas/core/apply.py | 4 +- pandas/core/arraylike.py | 7 +- pandas/core/arrays/arrow/_arrow_utils.py | 7 +- pandas/core/arrays/base.py | 2 +- pandas/core/arrays/categorical.py | 27 +-- pandas/core/arrays/datetimelike.py | 11 +- pandas/core/arrays/datetimes.py | 13 +- pandas/core/arrays/interval.py | 5 +- pandas/core/arrays/sparse/array.py | 17 +- pandas/core/arrays/sparse/dtype.py | 3 +- pandas/core/base.py | 3 +- pandas/core/common.py | 6 +- pandas/core/computation/align.py | 5 +- pandas/core/computation/eval.py | 3 +- pandas/core/computation/expressions.py | 3 +- pandas/core/config_init.py | 5 +- pandas/core/construction.py | 7 +- pandas/core/describe.py | 3 +- pandas/core/dtypes/astype.py | 6 +- pandas/core/dtypes/cast.py | 15 +- pandas/core/dtypes/common.py | 5 +- pandas/core/dtypes/concat.py | 3 +- pandas/core/dtypes/dtypes.py | 3 +- pandas/core/dtypes/inference.py | 3 +- pandas/core/frame.py | 29 +-- pandas/core/generic.py | 59 +++--- pandas/core/groupby/generic.py | 5 +- pandas/core/groupby/groupby.py | 16 +- pandas/core/groupby/grouper.py | 5 +- pandas/core/index.py | 3 +- pandas/core/indexers/utils.py | 5 +- pandas/core/indexes/accessors.py | 3 +- pandas/core/indexes/base.py | 53 ++--- pandas/core/indexes/category.py | 7 +- pandas/core/indexes/datetimelike.py | 3 +- pandas/core/indexes/datetimes.py | 15 +- pandas/core/indexes/interval.py | 3 +- pandas/core/indexes/multi.py | 23 ++- pandas/core/indexes/numeric.py | 3 +- pandas/core/indexes/period.py | 3 +- pandas/core/indexes/range.py | 9 +- pandas/core/indexing.py | 11 +- pandas/core/internals/__init__.py | 4 +- pandas/core/internals/blocks.py | 7 +- pandas/core/internals/construction.py | 3 +- pandas/core/internals/managers.py | 7 +- pandas/core/ops/__init__.py | 3 +- pandas/core/resample.py | 5 +- pandas/core/reshape/concat.py | 3 +- pandas/core/reshape/melt.py | 3 +- pandas/core/reshape/merge.py | 13 +- pandas/core/reshape/reshape.py | 3 +- pandas/core/series.py | 25 ++- pandas/core/strings/accessor.py | 11 +- pandas/core/tools/datetimes.py | 3 +- pandas/core/window/common.py | 3 +- pandas/core/window/ewm.py | 5 +- pandas/core/window/rolling.py | 10 +- pandas/io/clipboard/__init__.py | 8 +- pandas/io/clipboards.py | 7 +- pandas/io/common.py | 5 +- pandas/io/date_converters.py | 9 +- pandas/io/excel/_base.py | 9 +- pandas/io/formats/css.py | 9 +- pandas/io/formats/excel.py | 3 +- pandas/io/formats/style.py | 15 +- pandas/io/json/_table_schema.py | 5 +- pandas/io/parsers/base_parser.py | 5 +- pandas/io/parsers/c_parser_wrapper.py | 7 +- pandas/io/parsers/python_parser.py | 3 +- pandas/io/parsers/readers.py | 13 +- pandas/io/pytables.py | 15 +- pandas/io/sas/sas_xport.py | 3 +- pandas/io/sql.py | 9 +- pandas/io/stata.py | 17 +- pandas/plotting/_matplotlib/boxplot.py | 3 +- pandas/plotting/_matplotlib/core.py | 3 +- pandas/plotting/_matplotlib/style.py | 3 +- pandas/plotting/_matplotlib/tools.py | 7 +- pandas/tseries/frequencies.py | 5 +- pandas/util/_decorators.py | 2 +- pandas/util/_exceptions.py | 7 +- pandas/util/_validators.py | 5 +- pandas/util/testing.py | 3 +- scripts/list_future_warnings.sh | 2 +- 105 files changed, 587 insertions(+), 430 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index caeadf28728bf..db964c1f4d512 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -147,7 +147,7 @@ repos: # Check for deprecated messages without sphinx directive |(DEPRECATED|DEPRECATE|Deprecated)(:|,|\.) - # Check for ``stacklevel=5`` instead of ``stacklevel=find_stack_level()`` + # Check for ``stacklevel=5`` instead of ``stacklevel=find_stack_level(inspect.currentframe())`` |stacklevel=\d+ types_or: [python, cython, rst] - id: cython-casting diff --git a/doc/source/development/contributing_codebase.rst b/doc/source/development/contributing_codebase.rst index 0a7623ccf2ca8..bc85a54e61f22 100644 --- a/doc/source/development/contributing_codebase.rst +++ b/doc/source/development/contributing_codebase.rst @@ -134,7 +134,7 @@ Otherwise, you need to do it manually: warnings.warn( 'Use new_func instead.', FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_func() diff --git a/pandas/__init__.py b/pandas/__init__.py index b8382f783ad6a..75409dc7e8e53 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -1,5 +1,7 @@ from __future__ import annotations +import inspect + __docformat__ = "restructuredtext" # Let users know if they're missing any of our hard dependencies @@ -22,7 +24,11 @@ from pandas.compat import is_numpy_dev as _is_numpy_dev # pyright: ignore # noqa:F401 try: - from pandas._libs import hashtable as _hashtable, lib as _lib, tslib as _tslib + from pandas._libs import ( + hashtable as _hashtable, + lib as _lib, + tslib as _tslib, + ) except ImportError as _err: # pragma: no cover _module = _err.name raise ImportError( @@ -34,148 +40,137 @@ del _tslib, _lib, _hashtable from pandas._config import ( - get_option, - set_option, - reset_option, describe_option, + get_option, option_context, options, + reset_option, + set_option, ) -# let init-time option registration happen -import pandas.core.config_init # pyright: ignore # noqa:F401 +from pandas.util._print_versions import show_versions +from pandas.util._tester import test + +from pandas import ( + api, + arrays, + errors, + io, + plotting, + tseries, +) +from pandas import testing # noqa:PDF015 -from pandas.core.api import ( - # dtype +# use the closest tagged version if possible +from pandas._version import get_versions +from pandas.core.api import ( # dtype; missing; indexes; tseries; conversion; misc + NA, + BooleanDtype, + Categorical, + CategoricalDtype, + CategoricalIndex, + DataFrame, + DateOffset, + DatetimeIndex, + DatetimeTZDtype, + Flags, + Float32Dtype, + Float64Dtype, + Grouper, + Index, + IndexSlice, Int8Dtype, Int16Dtype, Int32Dtype, Int64Dtype, + Interval, + IntervalDtype, + IntervalIndex, + MultiIndex, + NamedAgg, + NaT, + Period, + PeriodDtype, + PeriodIndex, + RangeIndex, + Series, + StringDtype, + Timedelta, + TimedeltaIndex, + Timestamp, UInt8Dtype, UInt16Dtype, UInt32Dtype, UInt64Dtype, - Float32Dtype, - Float64Dtype, - CategoricalDtype, - PeriodDtype, - IntervalDtype, - DatetimeTZDtype, - StringDtype, - BooleanDtype, - # missing - NA, + array, + bdate_range, + date_range, + factorize, + interval_range, isna, isnull, notna, notnull, - # indexes - Index, - CategoricalIndex, - RangeIndex, - MultiIndex, - IntervalIndex, - TimedeltaIndex, - DatetimeIndex, - PeriodIndex, - IndexSlice, - # tseries - NaT, - Period, period_range, - Timedelta, + set_eng_float_format, timedelta_range, - Timestamp, - date_range, - bdate_range, - Interval, - interval_range, - DateOffset, - # conversion - to_numeric, to_datetime, + to_numeric, to_timedelta, - # misc - Flags, - Grouper, - factorize, unique, value_counts, - NamedAgg, - array, - Categorical, - set_eng_float_format, - Series, - DataFrame, ) - from pandas.core.arrays.sparse import SparseDtype - -from pandas.tseries.api import infer_freq -from pandas.tseries import offsets - from pandas.core.computation.api import eval +# let init-time option registration happen +import pandas.core.config_init # pyright: ignore # noqa:F401 from pandas.core.reshape.api import ( concat, + crosstab, + cut, + from_dummies, + get_dummies, lreshape, melt, - wide_to_long, merge, merge_asof, merge_ordered, - crosstab, pivot, pivot_table, - get_dummies, - from_dummies, - cut, qcut, + wide_to_long, ) -from pandas import api, arrays, errors, io, plotting, tseries -from pandas import testing # noqa:PDF015 -from pandas.util._print_versions import show_versions - -from pandas.io.api import ( - # excel +from pandas.io.api import ( # excel; parsers; pickle; pytables; sql; misc ExcelFile, ExcelWriter, - read_excel, - # parsers - read_csv, - read_fwf, - read_table, - # pickle - read_pickle, - to_pickle, - # pytables HDFStore, - read_hdf, - # sql - read_sql, - read_sql_query, - read_sql_table, - # misc read_clipboard, - read_parquet, - read_orc, + read_csv, + read_excel, read_feather, + read_fwf, read_gbq, + read_hdf, read_html, - read_xml, read_json, - read_stata, + read_orc, + read_parquet, + read_pickle, read_sas, read_spss, + read_sql, + read_sql_query, + read_sql_table, + read_stata, + read_table, + read_xml, + to_pickle, ) - from pandas.io.json import _json_normalize as json_normalize - -from pandas.util._tester import test - -# use the closest tagged version if possible -from pandas._version import get_versions +from pandas.tseries import offsets +from pandas.tseries.api import infer_freq v = get_versions() __version__ = v.get("closest-tag", v["version"]) @@ -204,9 +199,13 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.Index with the appropriate dtype instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), + ) + from pandas.core.api import ( + Float64Index, + Int64Index, + UInt64Index, ) - from pandas.core.api import Float64Index, Int64Index, UInt64Index return { "Float64Index": Float64Index, @@ -219,7 +218,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import from datetime module instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from datetime import datetime as dt @@ -233,7 +232,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import numpy directly instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) import numpy as np @@ -244,7 +243,7 @@ def __getattr__(name): f"The {name} class is removed from pandas. Accessing it from " "the top-level namespace will also be removed in the next version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return type(name, (), {}) @@ -256,7 +255,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.arrays.SparseArray instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from pandas.core.arrays.sparse import SparseArray as _SparseArray diff --git a/pandas/_config/config.py b/pandas/_config/config.py index 4ee42256e9a1a..fc35b95bba7dd 100644 --- a/pandas/_config/config.py +++ b/pandas/_config/config.py @@ -54,6 +54,7 @@ ContextDecorator, contextmanager, ) +import inspect import re from typing import ( Any, @@ -658,7 +659,11 @@ def _warn_if_deprecated(key: str) -> bool: d = _get_deprecated_option(key) if d: if d.msg: - warnings.warn(d.msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + d.msg, + FutureWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) else: msg = f"'{key}' is deprecated" if d.removal_ver: @@ -668,7 +673,9 @@ def _warn_if_deprecated(key: str) -> bool: else: msg += ", please refrain from using it." - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) return True return False diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index ee036b25b5ad4..fc6f770e819d8 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -228,7 +228,7 @@ def _warning_interval(inclusive: str | None = None, closed: None | lib.NoDefault warnings.warn( "Argument `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if closed is None: inclusive = "right" @@ -394,7 +394,7 @@ cdef class Interval(IntervalMixin): warnings.warn( "Attribute `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.inclusive diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 36f5f832bf607..6be1e38e63ed6 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -353,7 +353,7 @@ def fast_unique_multiple(list arrays, sort: bool = True): "The values in the array are unorderable. " "Pass `sort=False` to suppress this warning.", RuntimeWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) pass diff --git a/pandas/_libs/parsers.pyx b/pandas/_libs/parsers.pyx index 28029fd50837c..6dfce71703c6a 100644 --- a/pandas/_libs/parsers.pyx +++ b/pandas/_libs/parsers.pyx @@ -960,7 +960,7 @@ cdef class TextReader: "Defining usecols with out of bounds indices is deprecated " "and will raise a ParserError in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) results = {} @@ -1011,7 +1011,7 @@ cdef class TextReader: warnings.warn((f"Both a converter and dtype were specified " f"for column {name} - only the converter will " f"be used."), ParserWarning, - stacklevel=find_stack_level()) + stacklevel=find_stack_level(inspect.currentframe())) results[i] = _apply_converter(conv, self.parser, i, start, end) continue diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index d1a2dd19761d1..9056f21f8070f 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -844,7 +844,7 @@ cdef inline bint _parse_today_now(str val, int64_t* iresult, bint utc): "deprecated. In a future version, this will match Timestamp('now') " "and Timestamp.now()", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return True diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 519bc656488c0..938e563837d3f 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -289,7 +289,7 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit, "Conversion of non-round float with unit={unit} is ambiguous " "and will raise in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) ts = cast_from_unit(ts, unit) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index edf605318691f..8422c9421dc57 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -137,7 +137,7 @@ cdef class _NaT(datetime): "order to match the standard library behavior. " "In a future version these will be considered non-comparable.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return False @@ -381,7 +381,7 @@ class NaTType(_NaT): warnings.warn( "NaT.freq is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return None diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 02a4d1ffefd9e..abde6612de14a 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -471,7 +471,7 @@ cdef class BaseOffset: "DateOffset.__call__ is deprecated and will be removed in a future " "version. Use `offset + other` instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._apply(other) @@ -481,7 +481,7 @@ cdef class BaseOffset: f"{type(self).__name__}.apply is deprecated and will be removed " "in a future version. Use `offset + other` instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._apply(other) @@ -732,7 +732,7 @@ cdef class BaseOffset: warnings.warn( "onOffset is a deprecated, use is_on_offset instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.is_on_offset(dt) @@ -740,7 +740,7 @@ cdef class BaseOffset: warnings.warn( "isAnchored is a deprecated, use is_anchored instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.is_anchored() diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index 10df06958e87c..20a0e4535ce88 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -1,6 +1,7 @@ """ Parsing functions for datetime and datetime-like strings. """ +import inspect import re import time import warnings @@ -216,7 +217,7 @@ cdef inline object _parse_delimited_date(str date_string, bint dayfirst): format='MM/DD/YYYY', dayfirst='True', ), - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif not dayfirst and swapped_day_and_month: warnings.warn( @@ -224,7 +225,7 @@ cdef inline object _parse_delimited_date(str date_string, bint dayfirst): format='DD/MM/YYYY', dayfirst='False (the default)', ), - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # In Python <= 3.6.0 there is no range checking for invalid dates # in C api, thus we call faster C version for 3.6.1 or newer diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index a9d607ca9fd30..48a868e9d7bd2 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1829,7 +1829,7 @@ cdef class _Period(PeriodMixin): "be removed in a future version. Use " "`per.to_timestamp(...).tz_localize(tz)` instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) how = validate_end_alias(how) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 01395e27270ac..be008891c4455 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -685,7 +685,7 @@ cdef inline timedelta_from_spec(object number, object frac, object unit): "Units 'M', 'Y' and 'y' do not represent unambiguous " "timedelta values and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if unit == 'M': @@ -1057,7 +1057,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.freq is deprecated and will be removed in a future version", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return None @@ -1067,7 +1067,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.is_populated is deprecated and will be removed in a future version", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._is_populated @@ -1271,7 +1271,7 @@ cdef class _Timedelta(timedelta): warnings.warn( "Timedelta.delta is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.value diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 35de6f52445d2..6a1862513668f 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -254,7 +254,7 @@ cdef class _Timestamp(ABCTimestamp): warnings.warn( "Timestamp.freq is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._freq @@ -366,7 +366,7 @@ cdef class _Timestamp(ABCTimestamp): "In a future version these will be considered non-comparable. " "Use 'ts == pd.Timestamp(date)' or 'ts.date() == date' instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return NotImplemented else: @@ -667,7 +667,7 @@ cdef class _Timestamp(ABCTimestamp): "version. When you have a freq, use " f"freq.{field}(timestamp) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @property @@ -1173,7 +1173,7 @@ cdef class _Timestamp(ABCTimestamp): """ if self.nanosecond != 0 and warn: warnings.warn("Discarding nonzero nanoseconds in conversion.", - UserWarning, stacklevel=find_stack_level()) + UserWarning, stacklevel=find_stack_level(inspect.currentframe())) return datetime(self.year, self.month, self.day, self.hour, self.minute, self.second, @@ -1252,7 +1252,7 @@ cdef class _Timestamp(ABCTimestamp): warnings.warn( "Converting to Period representation will drop timezone information.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if freq is None: @@ -1261,7 +1261,7 @@ cdef class _Timestamp(ABCTimestamp): "In a future version, calling 'Timestamp.to_period()' without " "passing a 'freq' will raise an exception.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return Period(self, freq=freq) @@ -1453,7 +1453,7 @@ class Timestamp(_Timestamp): "Timestamp.utcfromtimestamp(ts).tz_localize(None). " "To get the future behavior, use Timestamp.fromtimestamp(ts, 'UTC')", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return cls(datetime.utcfromtimestamp(ts)) @@ -1689,7 +1689,7 @@ class Timestamp(_Timestamp): "as a wall time, not a UTC time. To interpret as a UTC time, " "use `Timestamp(dt64).tz_localize('UTC').tz_convert(tz)`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # Once this deprecation is enforced, we can do # return Timestamp(ts_input).tz_localize(tzobj) @@ -1706,7 +1706,7 @@ class Timestamp(_Timestamp): "The 'freq' argument in Timestamp is deprecated and will be " "removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if not is_offset_object(freq): freq = to_offset(freq) @@ -2042,7 +2042,7 @@ timedelta}, default 'raise' warnings.warn( "Timestamp.freqstr is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._freqstr diff --git a/pandas/_testing/asserters.py b/pandas/_testing/asserters.py index c7924dc451752..369e4b3454b65 100644 --- a/pandas/_testing/asserters.py +++ b/pandas/_testing/asserters.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect from typing import ( Literal, cast, @@ -112,7 +113,7 @@ def assert_almost_equal( "is deprecated and will be removed in a future version. " "You can stop passing 'check_less_precise' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) rtol = atol = _get_tol_from_less_precise(check_less_precise) @@ -339,7 +340,7 @@ def _get_ilevel_values(index, level): "is deprecated and will be removed in a future version. " "You can stop passing 'check_less_precise' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) rtol = atol = _get_tol_from_less_precise(check_less_precise) @@ -815,7 +816,7 @@ def assert_extension_array_equal( "is deprecated and will be removed in a future version. " "You can stop passing 'check_less_precise' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) rtol = atol = _get_tol_from_less_precise(check_less_precise) @@ -970,7 +971,7 @@ def assert_series_equal( "is deprecated and will be removed in a future version. " "You can stop passing 'check_less_precise' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) rtol = atol = _get_tol_from_less_precise(check_less_precise) @@ -1263,7 +1264,7 @@ def assert_frame_equal( "is deprecated and will be removed in a future version. " "You can stop passing 'check_less_precise' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) rtol = atol = _get_tol_from_less_precise(check_less_precise) diff --git a/pandas/compat/_optional.py b/pandas/compat/_optional.py index ef8bce30ecb50..fed8be0ff96b4 100644 --- a/pandas/compat/_optional.py +++ b/pandas/compat/_optional.py @@ -1,6 +1,7 @@ from __future__ import annotations import importlib +import inspect import sys import types import warnings @@ -160,7 +161,11 @@ def import_optional_dependency( f"(version '{version}' currently installed)." ) if errors == "warn": - warnings.warn(msg, UserWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, + UserWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) return None elif errors == "raise": raise ImportError(msg) diff --git a/pandas/compat/pickle_compat.py b/pandas/compat/pickle_compat.py index aa5d0cfd4e3eb..9e4492f5dbf89 100644 --- a/pandas/compat/pickle_compat.py +++ b/pandas/compat/pickle_compat.py @@ -5,6 +5,7 @@ import contextlib import copy +import inspect import io import pickle as pkl from typing import ( @@ -88,7 +89,7 @@ def __new__(cls) -> Series: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseSeries", new="Series"), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return Series(dtype=object) @@ -106,7 +107,7 @@ def __new__(cls) -> DataFrame: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseDataFrame", new="DataFrame"), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return DataFrame() diff --git a/pandas/core/accessor.py b/pandas/core/accessor.py index 07fa5799fe371..b66a91826b689 100644 --- a/pandas/core/accessor.py +++ b/pandas/core/accessor.py @@ -6,6 +6,7 @@ """ from __future__ import annotations +import inspect import warnings from pandas.util._decorators import doc @@ -268,7 +269,7 @@ def decorator(accessor): f"{repr(name)} for type {repr(cls)} is overriding a preexisting " f"attribute with the same name.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) setattr(cls, name, CachedAccessor(name, accessor)) cls._accessors.add(name) diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index 9cbe6b41a255e..7222e465cb710 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -836,7 +836,9 @@ def resolve_na_sentinel( "Specify `use_na_sentinel=True` to use the sentinel value -1, and " "`use_na_sentinel=False` to encode NaN values." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) result = na_sentinel return result @@ -1034,7 +1036,10 @@ def mode( try: npresult = np.sort(npresult) except TypeError as err: - warnings.warn(f"Unable to sort modes: {err}", stacklevel=find_stack_level()) + warnings.warn( + f"Unable to sort modes: {err}", + stacklevel=find_stack_level(inspect.currentframe()), + ) result = _reconstruct_data(npresult, original.dtype, original) return result @@ -1658,7 +1663,7 @@ def diff(arr, n: int, axis: int = 0): "dtype lost in 'diff()'. In the future this will raise a " "TypeError. Convert to a suitable dtype prior to calling 'diff'.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) arr = np.asarray(arr) dtype = arr.dtype diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 18a0f9b7aa2ce..7a7050ea8bad7 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -291,7 +291,7 @@ def transform_dict_like(self, func): f"raised, this will raise in a future version of pandas. " f"Drop these columns/ops to avoid this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return concat(results, axis=1) @@ -423,7 +423,7 @@ def agg_list_like(self) -> DataFrame | Series: warnings.warn( depr_nuisance_columns_msg.format(failed_names), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) try: diff --git a/pandas/core/arraylike.py b/pandas/core/arraylike.py index 280a599de84ed..4e8e4ea7e8d87 100644 --- a/pandas/core/arraylike.py +++ b/pandas/core/arraylike.py @@ -6,6 +6,7 @@ """ from __future__ import annotations +import inspect import operator from typing import Any import warnings @@ -220,7 +221,7 @@ def _maybe_fallback(ufunc: np.ufunc, method: str, *inputs: Any, **kwargs: Any): "or align manually (eg 'df1, df2 = df1.align(df2)') before passing to " "the ufunc to obtain the future behaviour and silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # keep the first dataframe of the inputs, other DataFrame/Series is @@ -348,7 +349,9 @@ def _reconstruct(result): "to an array with '.to_numpy()' first." ) warnings.warn( - msg.format(ufunc), FutureWarning, stacklevel=find_stack_level() + msg.format(ufunc), + FutureWarning, + stacklevel=find_stack_level(inspect.currentframe()), ) return result raise NotImplementedError diff --git a/pandas/core/arrays/arrow/_arrow_utils.py b/pandas/core/arrays/arrow/_arrow_utils.py index c9666de9f892d..81ba04a4e1426 100644 --- a/pandas/core/arrays/arrow/_arrow_utils.py +++ b/pandas/core/arrays/arrow/_arrow_utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import json import warnings @@ -22,7 +23,9 @@ def fallback_performancewarning(version: str | None = None) -> None: msg = "Falling back on a non-pyarrow code path which may decrease performance." if version is not None: msg += f" Upgrade to pyarrow >={version} to possibly suppress this warning." - warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, PerformanceWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) def pyarrow_array_to_numpy_and_mask( @@ -133,7 +136,7 @@ def closed(self) -> IntervalInclusiveType: warnings.warn( "Attribute `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._inclusive diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index 6c9b7adadb7b0..f268c24ca766d 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -476,7 +476,7 @@ def __init_subclass__(cls, **kwargs) -> None: f"instead. Add this argument to `{name}.factorize` to be compatible " f"with future versions of pandas and silence this warning.", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) def to_numpy( diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 234af0eb0d803..4898489b1d113 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2,6 +2,7 @@ from csv import QUOTE_NONNUMERIC from functools import partial +import inspect import operator from shutil import get_terminal_size from typing import ( @@ -394,7 +395,7 @@ def __init__( "Allowing scalars in the Categorical constructor is deprecated " "and will raise in a future version. Use `[value]` instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) values = [values] @@ -1010,7 +1011,7 @@ def set_categories( "a future version. Removing unused categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1125,7 +1126,7 @@ def rename_categories( "a future version. Removing unused categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1189,7 +1190,7 @@ def reorder_categories(self, new_categories, ordered=None, inplace=no_default): "a future version. Reordering categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1273,7 +1274,7 @@ def add_categories( "a future version. Removing unused categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1349,7 +1350,7 @@ def remove_categories(self, removals, inplace=no_default): "a future version. Removing unused categories will always " "return a new Categorical object.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1437,7 +1438,7 @@ def remove_unused_categories( "remove_unused_categories is deprecated and " "will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -2046,7 +2047,7 @@ def to_dense(self) -> np.ndarray: "Categorical.to_dense is deprecated and will be removed in " "a future version. Use np.asarray(cat) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return np.asarray(self) @@ -2063,7 +2064,7 @@ def _codes(self, value: np.ndarray): "Setting the codes on a Categorical is deprecated and will raise in " "a future version. Create a new Categorical object instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # GH#40606 NDArrayBacked.__init__(self, value, self.dtype) @@ -2088,7 +2089,7 @@ def take_nd( warn( "Categorical.take_nd is deprecated, use Categorical.take instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.take(indexer, allow_fill=allow_fill, fill_value=fill_value) @@ -2381,7 +2382,7 @@ def mode(self, dropna: bool = True) -> Categorical: "Categorical.mode is deprecated and will be removed in a future version. " "Use Series.mode instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._mode(dropna=dropna) @@ -2524,7 +2525,7 @@ def is_dtype_equal(self, other) -> bool: "Categorical.is_dtype_equal is deprecated and will be removed " "in a future version", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) try: return self._categories_match_up_to_permutation(other) @@ -2648,7 +2649,7 @@ def replace(self, to_replace, value, inplace: bool = False) -> Categorical | Non "Categorical.replace is deprecated and will be removed in a future " "version. Use Series.replace directly instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._replace(to_replace=to_replace, value=value, inplace=inplace) diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 471ecc5950dd9..253b582eddf2c 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -4,6 +4,7 @@ datetime, timedelta, ) +import inspect import operator from typing import ( TYPE_CHECKING, @@ -469,7 +470,7 @@ def astype(self, dtype, copy: bool = True): "exactly the specified dtype instead of uint64, and will " "raise if that conversion overflows.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif (self.asi8 < 0).any(): # GH#45034 @@ -479,7 +480,7 @@ def astype(self, dtype, copy: bool = True): "raise if the conversion overflows, as it did in this " "case with negative int64 values.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif dtype != np.int64: # GH#45034 @@ -489,7 +490,7 @@ def astype(self, dtype, copy: bool = True): "exactly the specified dtype instead of int64, and will " "raise if that conversion overflows.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if copy: @@ -628,7 +629,7 @@ def _validate_shift_value(self, fill_value): FutureWarning, # There is no way to hard-code the level since this might be # reached directly or called from the Index or Block method - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) fill_value = new_fill @@ -1372,7 +1373,7 @@ def _addsub_object_array(self, other: np.ndarray, op): "Adding/subtracting object-dtype array to " f"{type(self).__name__} not vectorized.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # Caller is responsible for broadcasting if necessary diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 5a3abe851fb7b..64c15df64de3b 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -6,6 +6,7 @@ timedelta, tzinfo, ) +import inspect from typing import ( TYPE_CHECKING, Literal, @@ -473,7 +474,7 @@ def _check_compatible_with(self, other, setitem: bool = False): "timezone. To retain the old behavior, explicitly cast to " "object dtype before the operation.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) raise ValueError(f"Timezones don't match. '{self.tz}' != '{other.tz}'") @@ -701,7 +702,7 @@ def _add_offset(self, offset) -> DatetimeArray: warnings.warn( "Non-vectorized DateOffset being applied to Series or DatetimeIndex.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) result = self.astype("O") + offset result = type(self)._from_sequence(result) @@ -1099,7 +1100,7 @@ def to_period(self, freq=None) -> PeriodArray: "Converting to PeriodArray/Index representation " "will drop timezone information.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if freq is None: @@ -1141,7 +1142,7 @@ def to_perioddelta(self, freq) -> TimedeltaArray: "Use `dtindex - dtindex.to_period(freq).to_timestamp()` instead.", FutureWarning, # stacklevel chosen to be correct for when called from DatetimeIndex - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from pandas.core.arrays.timedeltas import TimedeltaArray @@ -1343,7 +1344,7 @@ def weekofyear(self): "weekofyear and return an Index, you may call " "pd.Int64Index(idx.isocalendar().week)", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) week_series = self.isocalendar().week if week_series.hasnans: @@ -2240,7 +2241,7 @@ def maybe_convert_dtype(data, copy: bool, tz: tzinfo | None = None): "before passing the data to pandas. To get the future behavior, " "first cast to 'int64'.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif is_timedelta64_dtype(data.dtype) or is_bool_dtype(data.dtype): diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index e7198a95c07f1..bd765b4601b01 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import operator from operator import ( le, @@ -1380,7 +1381,7 @@ def closed(self) -> IntervalInclusiveType: warnings.warn( "Attribute `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.dtype.inclusive @@ -1432,7 +1433,7 @@ def set_closed( "set_closed is deprecated and will be removed in a future version. " "Use set_inclusive instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.set_inclusive(closed) diff --git a/pandas/core/arrays/sparse/array.py b/pandas/core/arrays/sparse/array.py index b1025038c9592..13ebd2b25e949 100644 --- a/pandas/core/arrays/sparse/array.py +++ b/pandas/core/arrays/sparse/array.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections import abc +import inspect import numbers import operator from typing import ( @@ -414,7 +415,7 @@ def __init__( "to construct an array with the desired repeats of the " "scalar value instead.\n\n", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if index is not None and not is_scalar(data): @@ -493,7 +494,7 @@ def __init__( "loses timezone information. Cast to object before " "sparse to retain timezone information.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) data = np.asarray(data, dtype="datetime64[ns]") if fill_value is NaT: @@ -777,7 +778,11 @@ def fillna( elif method is not None: msg = "fillna with 'method' requires high memory usage." - warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, + PerformanceWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) new_values = np.asarray(self) # interpolate_2d modifies new_values inplace interpolate_2d(new_values, method=method, limit=limit) @@ -1182,7 +1187,9 @@ def searchsorted( ) -> npt.NDArray[np.intp] | np.intp: msg = "searchsorted requires high memory usage." - warnings.warn(msg, PerformanceWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, PerformanceWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) if not is_scalar(v): v = np.asarray(v) v = np.asarray(v) @@ -1322,7 +1329,7 @@ def astype(self, dtype: AstypeArg | None = None, copy: bool = True): "array with the requested dtype. To retain the old behavior, use " "`obj.astype(SparseDtype(dtype))`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) dtype = self.dtype.update_dtype(dtype) diff --git a/pandas/core/arrays/sparse/dtype.py b/pandas/core/arrays/sparse/dtype.py index eaed6257736ba..cbe283b50b4f7 100644 --- a/pandas/core/arrays/sparse/dtype.py +++ b/pandas/core/arrays/sparse/dtype.py @@ -1,6 +1,7 @@ """Sparse Dtype""" from __future__ import annotations +import inspect import re from typing import ( TYPE_CHECKING, @@ -409,7 +410,7 @@ def _get_common_dtype(self, dtypes: list[DtypeObj]) -> DtypeObj | None: f"values: '{fill_values}'. Picking the first and " "converting the rest.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) np_dtypes = [x.subtype if isinstance(x, SparseDtype) else x for x in dtypes] diff --git a/pandas/core/base.py b/pandas/core/base.py index f7e6c4434da32..e1775628d09ee 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -4,6 +4,7 @@ from __future__ import annotations +import inspect import textwrap from typing import ( TYPE_CHECKING, @@ -1064,7 +1065,7 @@ def is_monotonic(self) -> bool: "is_monotonic is deprecated and will be removed in a future version. " "Use is_monotonic_increasing instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.is_monotonic_increasing diff --git a/pandas/core/common.py b/pandas/core/common.py index 980e7a79414ba..41ed68e73a4c0 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -169,7 +169,7 @@ def cast_scalar_indexer(val, warn_float: bool = False): "Indexing with a float is deprecated, and will raise an IndexError " "in pandas 2.0. You can manually convert to an integer key instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return int(val) return val @@ -697,4 +697,6 @@ def deprecate_numeric_only_default( "this warning." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) diff --git a/pandas/core/computation/align.py b/pandas/core/computation/align.py index 2e7a0f842ee6d..958e605727f27 100644 --- a/pandas/core/computation/align.py +++ b/pandas/core/computation/align.py @@ -7,6 +7,7 @@ partial, wraps, ) +import inspect from typing import ( TYPE_CHECKING, Callable, @@ -131,7 +132,9 @@ def _align_core(terms): f"by more than {ordm:.4g}; performance may suffer." ) warnings.warn( - w, category=PerformanceWarning, stacklevel=find_stack_level() + w, + category=PerformanceWarning, + stacklevel=find_stack_level(inspect.currentframe()), ) f = partial(ti.reindex, reindexer, axis=axis, copy=False) diff --git a/pandas/core/computation/eval.py b/pandas/core/computation/eval.py index ea70d0130a119..fa0ef46b850d1 100644 --- a/pandas/core/computation/eval.py +++ b/pandas/core/computation/eval.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect import tokenize from typing import TYPE_CHECKING import warnings @@ -311,7 +312,7 @@ def eval( "will be removed in a future version." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) exprs: list[str | BinOp] diff --git a/pandas/core/computation/expressions.py b/pandas/core/computation/expressions.py index afb4d0d549c45..a4b83fc557413 100644 --- a/pandas/core/computation/expressions.py +++ b/pandas/core/computation/expressions.py @@ -7,6 +7,7 @@ """ from __future__ import annotations +import inspect import operator import warnings @@ -216,7 +217,7 @@ def _bool_arith_fallback(op_str, a, b): f"evaluating in Python space because the {repr(op_str)} " "operator is not supported by numexpr for the bool dtype, " f"use {repr(_BOOL_OP_UNSUPPORTED[op_str])} instead.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return True return False diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index 8c1a3fece255e..6c32cc98df9ac 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -11,6 +11,7 @@ """ from __future__ import annotations +import inspect import os from typing import Callable import warnings @@ -370,7 +371,7 @@ def _deprecate_column_space(key): "in a future version. Use df.to_string(col_space=...) " "instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) cf.register_option("column_space", 12, validator=is_int, cb=_deprecate_column_space) @@ -397,7 +398,7 @@ def _deprecate_negative_int_max_colwidth(key): "will not be supported in future version. Instead, use None " "to not limit the column width.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) cf.register_option( diff --git a/pandas/core/construction.py b/pandas/core/construction.py index 4b63d492ec1dd..e1a69086609e9 100644 --- a/pandas/core/construction.py +++ b/pandas/core/construction.py @@ -6,6 +6,7 @@ """ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, Any, @@ -568,7 +569,7 @@ def sanitize_array( "passed dtype. To retain the old behavior, call Series(arr) or " "DataFrame(arr) without passing a dtype.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) subarr = np.array(data, copy=copy) except ValueError: @@ -580,7 +581,7 @@ def sanitize_array( "if they cannot be cast losslessly (matching Series behavior). " "To retain the old behavior, use DataFrame(data).astype(dtype)", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # GH#40110 until the deprecation is enforced, we _dont_ # ignore the dtype for DataFrame, and _do_ cast even though @@ -852,7 +853,7 @@ def _try_cast( "passed to 'DataFrame', either all columns will be cast to that " "dtype, or a TypeError will be raised.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) subarr = np.array(arr, dtype=object, copy=copy) return subarr diff --git a/pandas/core/describe.py b/pandas/core/describe.py index c70dbe0b8b0b1..d265a307078b9 100644 --- a/pandas/core/describe.py +++ b/pandas/core/describe.py @@ -9,6 +9,7 @@ ABC, abstractmethod, ) +import inspect from typing import ( TYPE_CHECKING, Any, @@ -373,7 +374,7 @@ def select_describe_func( "version of pandas. Specify `datetime_is_numeric=True` to " "silence this warning and adopt the future behavior now.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return describe_timestamp_as_categorical_1d elif is_timedelta64_dtype(data.dtype): diff --git a/pandas/core/dtypes/astype.py b/pandas/core/dtypes/astype.py index 7fb58468746a8..6d04dd755dbfd 100644 --- a/pandas/core/dtypes/astype.py +++ b/pandas/core/dtypes/astype.py @@ -371,7 +371,7 @@ def astype_dt64_to_dt64tz( "timezone-aware dtype is deprecated and will raise in a " "future version. Use ser.dt.tz_localize instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # GH#33401 this doesn't match DatetimeArray.astype, which @@ -387,7 +387,7 @@ def astype_dt64_to_dt64tz( "timezone-aware dtype is deprecated and will raise in a " "future version. Use obj.tz_localize instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return values.tz_localize(dtype.tz) @@ -407,7 +407,7 @@ def astype_dt64_to_dt64tz( "future version. Use obj.tz_localize(None) or " "obj.tz_convert('UTC').tz_localize(None) instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) result = values.tz_convert("UTC").tz_localize(None) diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 769656d1c4755..5340bc6b590c4 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -10,6 +10,7 @@ timedelta, ) import functools +import inspect from typing import ( TYPE_CHECKING, Any, @@ -624,7 +625,7 @@ def _maybe_promote(dtype: np.dtype, fill_value=np.nan): "dtype is deprecated. In a future version, this will be cast " "to object dtype. Pass `fill_value=Timestamp(date_obj)` instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return dtype, fv elif isinstance(fill_value, str): @@ -1277,7 +1278,7 @@ def try_timedelta(v: np.ndarray) -> np.ndarray: "and will be removed in a future version. To retain the old behavior " f"explicitly pass Series(data, dtype={value.dtype})", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return value @@ -1336,7 +1337,7 @@ def maybe_cast_to_datetime( "`pd.Series(values).dt.tz_localize(None)` " "instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # equiv: dta.view(dtype) # Note: NOT equivalent to dta.astype(dtype) @@ -1376,7 +1377,7 @@ def maybe_cast_to_datetime( ".tz_localize('UTC').tz_convert(dtype.tz) " "or pd.Series(data.view('int64'), dtype=dtype)", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) value = dta.tz_localize("UTC").tz_convert(dtype.tz) @@ -1745,7 +1746,7 @@ def _maybe_unbox_datetimelike_tz_deprecation(value: Scalar, dtype: DtypeObj): "`pd.Series(values).dt.tz_localize(None)` " "instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_value = value.tz_localize(None) return _maybe_unbox_datetimelike(new_value, dtype) @@ -1863,7 +1864,7 @@ def maybe_cast_to_integer_array( "In a future version this will raise OverflowError. To retain the " f"old behavior, use pd.Series(values).astype({dtype})", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return casted @@ -1874,7 +1875,7 @@ def maybe_cast_to_integer_array( f"dtype={dtype} is deprecated and will raise in a future version. " "Use values.view(dtype) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return casted diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index c10461b2fc7f8..be4d50af8a053 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect from typing import ( Any, Callable, @@ -307,7 +308,7 @@ def is_categorical(arr) -> bool: "is_categorical is deprecated and will be removed in a future version. " "Use is_categorical_dtype instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return isinstance(arr, ABCCategorical) or is_categorical_dtype(arr) @@ -1386,7 +1387,7 @@ def is_extension_type(arr) -> bool: "'is_extension_type' is deprecated and will be removed in a future " "version. Use 'is_extension_array_dtype' instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if is_categorical_dtype(arr): diff --git a/pandas/core/dtypes/concat.py b/pandas/core/dtypes/concat.py index 059df4009e2f6..80efe96ae7146 100644 --- a/pandas/core/dtypes/concat.py +++ b/pandas/core/dtypes/concat.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, cast, @@ -152,7 +153,7 @@ def is_nonempty(x) -> bool: "(instead of coercing bools to numeric values). To retain the old " "behavior, explicitly cast bool-dtype arrays to numeric dtype.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return result diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 99b2082d409a9..c2c600adbbe09 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect import re from typing import ( TYPE_CHECKING, @@ -1194,7 +1195,7 @@ def closed(self): warnings.warn( "Attribute `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._inclusive diff --git a/pandas/core/dtypes/inference.py b/pandas/core/dtypes/inference.py index 893e4a9be58ef..78cf76e747d1d 100644 --- a/pandas/core/dtypes/inference.py +++ b/pandas/core/dtypes/inference.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections import abc +import inspect from numbers import Number import re from typing import Pattern @@ -459,7 +460,7 @@ def is_inferred_bool_dtype(arr: ArrayLike) -> bool: "will not be included in reductions with bool_only=True. " "Explicitly cast to bool dtype instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return result diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 49e5bc24786dd..0a7a6494d04eb 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -14,6 +14,7 @@ from collections import abc import datetime import functools +import inspect from io import StringIO import itertools from textwrap import dedent @@ -673,7 +674,7 @@ def __init__( "removed in a future version. Pass " "{name: data[name] for name in data.dtype.names} instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # a masked array @@ -1324,7 +1325,7 @@ def iteritems(self) -> Iterable[tuple[Hashable, Series]]: "iteritems is deprecated and will be removed in a future version. " "Use .items instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) yield from self.items() @@ -1909,7 +1910,7 @@ def to_dict(self, orient: str = "dict", into=dict): warnings.warn( "DataFrame columns are not unique, some columns will be omitted.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # GH16122 into_c = com.standardize_mapping(into) @@ -1930,7 +1931,7 @@ def to_dict(self, orient: str = "dict", into=dict): "will be used in a future version. Use one of the above " "to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if orient.startswith("d"): @@ -2773,7 +2774,7 @@ def to_markdown( "'showindex' is deprecated. Only 'index' will be used " "in a future version. Use 'index' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) kwargs.setdefault("headers", "keys") @@ -3387,7 +3388,7 @@ def info( warnings.warn( "null_counts is deprecated. Use show_counts instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) show_counts = null_counts info = DataFrameInfo( @@ -3772,7 +3773,7 @@ def _getitem_bool_array(self, key): warnings.warn( "Boolean Series key will be reindexed to match DataFrame index.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif len(key) != len(self.index): raise ValueError( @@ -4862,7 +4863,9 @@ def lookup( "You can use DataFrame.melt and DataFrame.loc " "as a substitute." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) n = len(row_labels) if n != len(col_labels): @@ -8364,7 +8367,7 @@ def groupby( "will be removed in a future version." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: squeeze = False @@ -9735,7 +9738,7 @@ def append( "and will be removed from pandas in a future version. " "Use pandas.concat instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._append(other, ignore_index, verify_integrity, sort) @@ -10701,7 +10704,7 @@ def count( "deprecated and will be removed in a future version. Use groupby " "instead. df.count(level=1) should use df.groupby(level=1).count().", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) res = self._count_level(level, axis=axis, numeric_only=numeric_only) return res.__finalize__(self, method="count") @@ -10803,7 +10806,7 @@ def _reduce( "will include datetime64 and datetime64tz columns in a " "future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # Non-copy equivalent to # dt64_cols = self.dtypes.apply(is_datetime64_any_dtype) @@ -10904,7 +10907,7 @@ def _get_data() -> DataFrame: "version this will raise TypeError. Select only valid " "columns before calling the reduction.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if hasattr(result, "dtype"): diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 8122031dbe26b..adf376d771667 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -5,6 +5,7 @@ from datetime import timedelta import functools import gc +import inspect import json import operator import pickle @@ -493,7 +494,7 @@ def _AXIS_NUMBERS(self) -> dict[str, int]: warnings.warn( "_AXIS_NUMBERS has been deprecated.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return {"index": 0} @@ -2039,7 +2040,7 @@ def __array_wrap__( "The __array_wrap__ method of DataFrame and Series will be removed in " "a future version", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) res = lib.item_from_zerodim(result) if is_scalar(res): @@ -3375,7 +3376,9 @@ def to_latex( "to use `DataFrame.style.to_latex` which also contains additional " "functionality." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) # Get defaults from the pandas config if self.ndim == 1: @@ -3804,7 +3807,7 @@ class max_speed "is_copy is deprecated and will be removed in a future version. " "'take' always returns a copy, so there is no need to specify this.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) nv.validate_take((), kwargs) @@ -3960,7 +3963,7 @@ class animal locomotion "Passing lists as key for xs is deprecated and will be removed in a " "future version. Pass key as a tuple instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if level is not None: @@ -4145,7 +4148,11 @@ def _check_setitem_copy(self, t="setting", force=False): if value == "raise": raise SettingWithCopyError(t) elif value == "warn": - warnings.warn(t, SettingWithCopyWarning, stacklevel=find_stack_level()) + warnings.warn( + t, + SettingWithCopyWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) def __delitem__(self, key) -> None: """ @@ -5883,7 +5890,7 @@ def __setattr__(self, name: str, value) -> None: "created via a new attribute name - see " "https://pandas.pydata.org/pandas-docs/" "stable/indexing.html#attribute-access", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) object.__setattr__(self, name, value) @@ -8262,7 +8269,7 @@ def between_time( "`include_start` and `include_end` are deprecated in " "favour of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) left = True if include_start is lib.no_default else include_start right = True if include_end is lib.no_default else include_end @@ -8978,7 +8985,7 @@ def rank( "and will raise in a future version. Pass either 'True' or " "'False'. 'False' will be the default.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) warned = True elif numeric_only is lib.no_default: @@ -9034,7 +9041,7 @@ def ranker(data): "is deprecated; in a future version this will raise TypeError. " "Select only valid columns before calling rank.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if numeric_only: @@ -9045,7 +9052,7 @@ def ranker(data): f"{self.dtype} is deprecated and will raise a TypeError in a " "future version of pandas", category=FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) data = self._get_numeric_data() else: @@ -9816,7 +9823,7 @@ def where( "try_cast keyword is deprecated and will be removed in a " "future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._where(cond, other, inplace, axis, level) @@ -9894,7 +9901,7 @@ def mask( "try_cast keyword is deprecated and will be removed in a " "future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # see gh-21891 @@ -10089,7 +10096,9 @@ def slice_shift(self: NDFrameT, periods: int = 1, axis=0) -> NDFrameT: "and will be removed in a future version. " "You can use DataFrame/Series.shift instead." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) if periods == 0: return self @@ -10142,7 +10151,7 @@ def tshift(self: NDFrameT, periods: int = 1, freq=None, axis: Axis = 0) -> NDFra "Please use shift instead." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if freq is None: @@ -10975,7 +10984,7 @@ def _logical_func( "deprecated and will be removed in a future version. Use groupby " "instead. df.any(level=1) should use df.groupby(level=1).any()", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if bool_only is not None: raise NotImplementedError( @@ -11109,7 +11118,7 @@ def _stat_function_ddof( "deprecated and will be removed in a future version. Use groupby " "instead. df.var(level=1) should use df.groupby(level=1).var().", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._agg_by_level( name, axis=axis, level=level, skipna=skipna, ddof=ddof @@ -11183,7 +11192,7 @@ def _stat_function( f"scalar {name} over the entire DataFrame. To retain the old " f"behavior, use 'frame.{name}(axis=0)' or just 'frame.{name}()'", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if axis is lib.no_default: axis = None @@ -11196,7 +11205,7 @@ def _stat_function( "deprecated and will be removed in a future version. Use groupby " "instead. df.median(level=1) should use df.groupby(level=1).median().", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._agg_by_level( name, axis=axis, level=level, skipna=skipna, numeric_only=numeric_only @@ -11320,7 +11329,7 @@ def _min_count_stat_function( "deprecated and will be removed in a future version. Use groupby " "instead. df.sum(level=1) should use df.groupby(level=1).sum().", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._agg_by_level( name, @@ -11408,7 +11417,9 @@ def mad( "The 'mad' method is deprecated and will be removed in a future version. " "To compute the same result, you may do `(df - df.mean()).abs().mean()`." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) if not is_bool(skipna): warnings.warn( @@ -11416,7 +11427,7 @@ def mad( "version. Pass True instead. Only boolean values will be allowed " "in the future.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) skipna = True if axis is None: @@ -11427,7 +11438,7 @@ def mad( "deprecated and will be removed in a future version. Use groupby " "instead. df.mad(level=1) should use df.groupby(level=1).mad()", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._agg_by_level("mad", axis=axis, level=level, skipna=skipna) @@ -11874,7 +11885,7 @@ def expanding( warnings.warn( "The `center` argument on `expanding` will be removed in the future.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: center = False diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 0f9befa7cff78..8a261f09e7118 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -9,6 +9,7 @@ from collections import abc from functools import partial +import inspect from textwrap import dedent from typing import ( TYPE_CHECKING, @@ -1235,7 +1236,7 @@ def _transform_general(self, func, *args, **kwargs): "`.to_numpy()` to the result in the transform function to keep " "the current behavior and silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) concat_index = obj.columns if self.axis == 0 else obj.index @@ -1405,7 +1406,7 @@ def __getitem__(self, key) -> DataFrameGroupBy | SeriesGroupBy: "Indexing with multiple keys (implicitly converted to a tuple " "of keys) will be deprecated, use a list instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return super().__getitem__(key) diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 8e0ed959fabc3..138474e21fb57 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -833,7 +833,7 @@ def __iter__(self) -> Iterator[tuple[Hashable, NDFrameT]]: "to avoid this warning." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.grouper.get_iterator(self._selected_obj, axis=self.axis) @@ -1357,7 +1357,7 @@ def _resolve_numeric_only( f"numeric_only={numeric_only} and dtype {self.obj.dtype}. This will " "raise a TypeError in a future version of pandas", category=FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) raise NotImplementedError( f"{type(self).__name__}.{how} does not implement numeric_only" @@ -1619,7 +1619,9 @@ def _python_apply_general( "To adopt the future behavior and silence this warning, use " "\n\n\t>>> .groupby(..., group_keys=True)" ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) # We want to behave as if `self.group_keys=False` when reconstructing # the object. However, we don't want to mutate the stateful GroupBy # object, so we just override it. @@ -2940,7 +2942,7 @@ def pad(self, limit=None): "pad is deprecated and will be removed in a future version. " "Use ffill instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.ffill(limit=limit) @@ -2976,7 +2978,7 @@ def backfill(self, limit=None): "backfill is deprecated and will be removed in a future version. " "Use bfill instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.bfill(limit=limit) @@ -4362,7 +4364,7 @@ def warn_dropping_nuisance_columns_deprecated(cls, how: str, numeric_only) -> No f"Before calling .{how}, select only columns which " "should be valid for the function.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif numeric_only is lib.no_default: warnings.warn( @@ -4372,5 +4374,5 @@ def warn_dropping_nuisance_columns_deprecated(cls, how: str, numeric_only) -> No f"Either specify numeric_only or select only columns which " "should be valid for the function.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py index b9f4166b475ca..04ebc00b8e964 100644 --- a/pandas/core/groupby/grouper.py +++ b/pandas/core/groupby/grouper.py @@ -4,6 +4,7 @@ """ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, Any, @@ -981,7 +982,7 @@ def _check_deprecated_resample_kwargs(kwargs, origin): "\nbecomes:\n" '\n>>> df.resample(freq="3s", offset="2s")\n', FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if kwargs.get("loffset", None) is not None: warnings.warn( @@ -992,5 +993,5 @@ def _check_deprecated_resample_kwargs(kwargs, origin): '\n>>> df = df.resample(freq="3s").mean()' '\n>>> df.index = df.index.to_timestamp() + to_offset("8H")\n', FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/pandas/core/index.py b/pandas/core/index.py index 19e9c6b27e4e7..519a82d680426 100644 --- a/pandas/core/index.py +++ b/pandas/core/index.py @@ -1,6 +1,7 @@ # pyright: reportUnusedImport = false from __future__ import annotations +import inspect import warnings from pandas.util._exceptions import find_stack_level @@ -31,7 +32,7 @@ "pandas.core.index is deprecated and will be removed in a future version. " "The public classes are available in the top-level namespace.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) __all__: list[str] = [] diff --git a/pandas/core/indexers/utils.py b/pandas/core/indexers/utils.py index 0f3cdc4195c85..70e6ff8ab7783 100644 --- a/pandas/core/indexers/utils.py +++ b/pandas/core/indexers/utils.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, Any, @@ -348,7 +349,7 @@ def deprecate_ndim_indexing(result, stacklevel: int = 3) -> None: "is deprecated and will be removed in a future " "version. Convert to a numpy array before indexing instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @@ -372,7 +373,7 @@ def unpack_1tuple(tup): "slice is deprecated and will raise in a future " "version. Pass a tuple instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return tup[0] diff --git a/pandas/core/indexes/accessors.py b/pandas/core/indexes/accessors.py index 46959aa5cd3e2..dea38e2ed2907 100644 --- a/pandas/core/indexes/accessors.py +++ b/pandas/core/indexes/accessors.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect from typing import TYPE_CHECKING import warnings @@ -291,7 +292,7 @@ def weekofyear(self): "Series.dt.weekofyear and Series.dt.week have been deprecated. " "Please use Series.dt.isocalendar().week instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) week_series = self.isocalendar().week week_series.name = self.name diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index e8cb412b12f59..d56a21f5a0d73 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -2,6 +2,7 @@ from datetime import datetime import functools +import inspect from itertools import zip_longest import operator from typing import ( @@ -437,7 +438,7 @@ def __new__( "'tupleize_cols' is deprecated and will raise TypeError in a " "future version. Use the specific Index subclass directly instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from pandas.core.arrays import PandasArray @@ -615,7 +616,7 @@ def _dtype_to_subclass(cls, dtype: DtypeObj): "dense numpy ndarray. To retain the old behavior, use " "pd.Index(arr.to_numpy()) instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return cls._dtype_to_subclass(dtype.subtype) @@ -683,7 +684,7 @@ def asi8(self): warnings.warn( "Index.asi8 is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return None @@ -797,7 +798,7 @@ def _get_attributes_dict(self) -> dict[str_t, Any]: "The Index._get_attributes_dict method is deprecated, and will be " "removed in a future version", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return {k: getattr(self, k, None) for k in self._attributes} @@ -1000,7 +1001,7 @@ def ravel(self, order="C"): "Index.ravel returning ndarray is deprecated; in a future version " "this will return a view on self.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if needs_i8_conversion(self.dtype): # Item "ndarray[Any, Any]" of "Union[ExtensionArray, ndarray[Any, Any]]" @@ -1295,7 +1296,7 @@ def copy( "parameter names is deprecated and will be removed in a future " "version. Use the name parameter instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) name = self._validate_names(name=name, names=names, deep=deep)[0] @@ -1310,7 +1311,7 @@ def copy( "parameter dtype is deprecated and will be removed in a future " "version. Use the astype method instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_index = new_index.astype(dtype) return new_index @@ -1502,7 +1503,7 @@ def to_native_types(self, slicer=None, **kwargs) -> np.ndarray: "The 'to_native_types' method is deprecated and will be removed in " "a future version. Use 'astype(str)' instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) values = self if slicer is not None: @@ -1703,7 +1704,7 @@ def to_frame( "the future `None` will be used as the name of the resulting " "DataFrame column.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) name = lib.no_default @@ -2289,7 +2290,7 @@ def is_monotonic(self) -> bool: "is_monotonic is deprecated and will be removed in a future version. " "Use is_monotonic_increasing instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.is_monotonic_increasing @@ -2714,7 +2715,7 @@ def is_mixed(self) -> bool: "Index.is_mixed is deprecated and will be removed in a future version. " "Check index.inferred_type directly instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.inferred_type in ["mixed"] @@ -2759,7 +2760,7 @@ def is_all_dates(self) -> bool: "Index.is_all_dates is deprecated, will be removed in a future version. " "check index.inferred_type instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._is_all_dates @@ -3140,7 +3141,7 @@ def __and__(self, other): "in the future this will be a logical operation matching " "Series.__and__. Use index.intersection(other) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.intersection(other) @@ -3151,7 +3152,7 @@ def __or__(self, other): "in the future this will be a logical operation matching " "Series.__or__. Use index.union(other) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.union(other) @@ -3162,7 +3163,7 @@ def __xor__(self, other): "in the future this will be a logical operation matching " "Series.__xor__. Use index.symmetric_difference(other) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.symmetric_difference(other) @@ -3218,7 +3219,7 @@ def _deprecate_dti_setop(self, other: Index, setop: str_t): "object dtype. To retain the old behavior, " f"use `index.astype(object).{setop}(other)`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @final @@ -3794,7 +3795,7 @@ def get_loc(self, key, method=None, tolerance=None): "and will raise in a future version. Use " "index.get_indexer([item], method=...) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if is_scalar(key) and isna(key) and not self.hasnans: @@ -4258,7 +4259,7 @@ def is_int(v): "lookups. To retain the old behavior, use `series.iloc[i:j]`. " "To get the future behavior, use `series.loc[i:j]`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if self.is_integer() or is_index_slice: # Note: these checks are redundant if we know is_index_slice @@ -4292,7 +4293,7 @@ def is_int(v): "and will raise TypeError in a future version. " "Use .loc with labels or .iloc with positions instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) indexer = key else: @@ -4443,7 +4444,7 @@ def reindex( "reindexing with a non-unique Index is deprecated and " "will raise in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) target = self._wrap_reindex_result(target, indexer, preserve_names) @@ -5257,7 +5258,7 @@ def is_type_compatible(self, kind: str_t) -> bool: "Index.is_type_compatible is deprecated and will be removed in a " "future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return kind == self.inferred_type @@ -5904,7 +5905,7 @@ def get_value(self, series: Series, key): "get_value is deprecated and will be removed in a future version. " "Use Series[key] instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self._check_indexing_error(key) @@ -5972,7 +5973,7 @@ def set_value(self, arr, key, value) -> None: "will be removed in a future version." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) loc = self._engine.get_loc(key) if not can_hold_element(arr, value): @@ -7238,7 +7239,7 @@ def _deprecated_arg(self, value, name: str_t, methodname: str_t) -> None: f"'{name}' argument in {methodname} is deprecated " "and will be removed in a future version. Do not pass it.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @@ -7436,7 +7437,7 @@ def _maybe_cast_data_without_dtype( "In a future version, the Index constructor will not infer numeric " "dtypes when passed object-dtype sequences (matching Series behavior)", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) result = ensure_wrapped_if_datetimelike(result) return result @@ -7492,6 +7493,6 @@ def _maybe_try_sort(result, sort): warnings.warn( f"{err}, sort order is undefined for incomparable objects.", RuntimeWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return result diff --git a/pandas/core/indexes/category.py b/pandas/core/indexes/category.py index c1ae3cb1b16ea..e068c1434fd4e 100644 --- a/pandas/core/indexes/category.py +++ b/pandas/core/indexes/category.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect from typing import ( Any, Hashable, @@ -224,7 +225,7 @@ def __new__( "deprecated and will raise in a future version. " "Use CategoricalIndex([], ...) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) data = [] @@ -419,7 +420,7 @@ def reindex( "reindexing with a non-unique Index is deprecated and will " "raise in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_target: Index @@ -495,7 +496,7 @@ def take_nd(self, *args, **kwargs) -> CategoricalIndex: "CategoricalIndex.take_nd is deprecated, use CategoricalIndex.take " "instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.take(*args, **kwargs) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 8014d010afc1b..84955d5137383 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -4,6 +4,7 @@ from __future__ import annotations from datetime import datetime +import inspect from typing import ( TYPE_CHECKING, Any, @@ -393,7 +394,7 @@ def is_type_compatible(self, kind: str) -> bool: f"{type(self).__name__}.is_type_compatible is deprecated and will be " "removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return kind in self._data._infer_matches diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 30c770f32c2dc..2625d8c683a0c 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -7,6 +7,7 @@ timedelta, tzinfo, ) +import inspect import operator from typing import ( TYPE_CHECKING, @@ -423,7 +424,7 @@ def union_many(self, others): "DatetimeIndex.union_many is deprecated and will be removed in " "a future version. Use obj.union instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) this = self @@ -547,7 +548,7 @@ def to_series(self, keep_tz=lib.no_default, index=None, name=None): "is deprecated and will be removed in a future version. " "You can stop passing 'keep_tz' to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: warnings.warn( @@ -557,7 +558,7 @@ def to_series(self, keep_tz=lib.no_default, index=None, name=None): "can do 'idx.tz_convert(None)' before calling " "'to_series'.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: keep_tz = True @@ -660,7 +661,9 @@ def _deprecate_mismatched_indexing(self, key, one_way: bool = False) -> None: "raise KeyError in a future version. " "Use a timezone-aware object instead." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) def get_loc(self, key, method=None, tolerance=None): """ @@ -809,7 +812,7 @@ def check_str_or_none(point): "with non-existing keys is deprecated and will raise a " "KeyError in a future Version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) indexer = mask.nonzero()[0][::step] if len(indexer) == len(self): @@ -1089,7 +1092,7 @@ def date_range( warnings.warn( "Argument `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if closed is None: inclusive = "both" diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 23f2e724e208c..5ed8f79bbbefe 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -1,6 +1,7 @@ """ define the IntervalIndex """ from __future__ import annotations +import inspect from operator import ( le, lt, @@ -242,7 +243,7 @@ def closed(self): warnings.warn( "Attribute `closed` is deprecated in favor of `inclusive`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.inclusive diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 5a9b1e6943608..b282455cf6051 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1,6 +1,7 @@ from __future__ import annotations from functools import wraps +import inspect from sys import getsizeof from typing import ( TYPE_CHECKING, @@ -923,7 +924,7 @@ def set_levels( warnings.warn( "inplace is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1084,7 +1085,7 @@ def set_codes(self, codes, level=None, inplace=None, verify_integrity: bool = Tr warnings.warn( "inplace is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: inplace = False @@ -1197,7 +1198,7 @@ def copy( "parameter levels is deprecated and will be removed in a future " "version. Use the set_levels method instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) keep_id = False if codes is not None: @@ -1205,7 +1206,7 @@ def copy( "parameter codes is deprecated and will be removed in a future " "version. Use the set_codes method instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) keep_id = False @@ -1237,7 +1238,7 @@ def copy( "parameter dtype is deprecated and will be removed in a future " "version. Use the astype method instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_index = new_index.astype(dtype) return new_index @@ -1800,7 +1801,7 @@ def to_frame( "the future `None` will be used as the name of the resulting " "DataFrame column.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) name = lib.no_default @@ -1869,7 +1870,7 @@ def is_lexsorted(self) -> bool: "MultiIndex.is_lexsorted is deprecated as a public function, " "users should use MultiIndex.is_monotonic_increasing instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._is_lexsorted() @@ -1913,7 +1914,7 @@ def lexsort_depth(self) -> int: "MultiIndex.is_lexsorted is deprecated as a public function, " "users should use MultiIndex.is_monotonic_increasing instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._lexsort_depth @@ -2279,7 +2280,7 @@ def drop(self, codes, level=None, errors="raise"): "dropping on a non-lexsorted multi-index " "without a level parameter may impact performance.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) loc = loc.nonzero()[0] inds.extend(loc) @@ -2955,7 +2956,7 @@ def _maybe_to_slice(loc): warnings.warn( "indexing past lexsort depth may impact performance.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) loc = np.arange(start, stop, dtype=np.intp) @@ -3394,7 +3395,7 @@ def _to_bool_indexer(indexer) -> npt.NDArray[np.bool_]: # TODO: how to handle IntervalIndex level? # (no test cases) FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) continue else: diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index a597bea0eb724..d114fe47fa0f1 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect from typing import ( Callable, Hashable, @@ -360,7 +361,7 @@ def asi8(self) -> npt.NDArray[np.int64]: warnings.warn( "Index.asi8 is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._values.view(self._default_dtype) diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index c034d9416eae7..fedcba7aa9644 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -4,6 +4,7 @@ datetime, timedelta, ) +import inspect from typing import Hashable import warnings @@ -366,7 +367,7 @@ def astype(self, dtype, copy: bool = True, how=lib.no_default): "will be removed in a future version. " "Use index.to_timestamp(how=how) instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: how = "start" diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index 376c98b6e176f..9f49c7456d9ce 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -1,6 +1,7 @@ from __future__ import annotations from datetime import timedelta +import inspect import operator from sys import getsizeof from typing import ( @@ -263,7 +264,7 @@ def _start(self) -> int: warnings.warn( self._deprecation_message.format("_start", "start"), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.start @@ -286,7 +287,7 @@ def _stop(self) -> int: warnings.warn( self._deprecation_message.format("_stop", "stop"), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.stop @@ -310,7 +311,7 @@ def _step(self) -> int: warnings.warn( self._deprecation_message.format("_step", "step"), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.step @@ -471,7 +472,7 @@ def copy( "parameter dtype is deprecated and will be removed in a future " "version. Use the astype method instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) new_index = new_index.astype(dtype) return new_index diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 4e242e33627a4..b143e1e50aa6c 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1,6 +1,7 @@ from __future__ import annotations from contextlib import suppress +import inspect from typing import ( TYPE_CHECKING, Hashable, @@ -1497,7 +1498,7 @@ def _has_valid_setitem_indexer(self, indexer) -> bool: "a future version.\n" "consider using .loc with a DataFrame indexer for automatic alignment.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if not isinstance(indexer, tuple): @@ -2026,7 +2027,7 @@ def _setitem_single_column(self, loc: int, value, plane_indexer): "`df[df.columns[i]] = newvals` or, if columns are non-unique, " "`df.isetitem(i, newvals)`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # TODO: how to get future behavior? # TODO: what if we got here indirectly via loc? @@ -2502,7 +2503,7 @@ def convert_to_index_sliceable(obj: DataFrame, key): "and will be removed in a future version. Use `frame.loc[string]` " "instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return res except (KeyError, ValueError, NotImplementedError): @@ -2656,7 +2657,7 @@ def check_deprecated_indexers(key) -> None: "Passing a set as an indexer is deprecated and will raise in " "a future version. Use a list instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if ( isinstance(key, dict) @@ -2667,5 +2668,5 @@ def check_deprecated_indexers(key) -> None: "Passing a dict as an indexer is deprecated and will raise in " "a future version. Use a list instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index ea69b567611e4..a4bd1f274066e 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -1,3 +1,5 @@ +import inspect + from pandas.core.internals.api import make_block from pandas.core.internals.array_manager import ( ArrayManager, @@ -50,7 +52,7 @@ def __getattr__(name: str): "CategoricalBlock is deprecated and will be removed in a future version. " "Use ExtensionBlock instead.", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from pandas.core.internals.blocks import CategoricalBlock diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 46c375b92dd83..3e27cf0b15511 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1,6 +1,7 @@ from __future__ import annotations from functools import wraps +import inspect import re from typing import ( TYPE_CHECKING, @@ -181,7 +182,7 @@ def is_categorical(self) -> bool: "future version. Use isinstance(block.values, Categorical) " "instead. See https://github.com/pandas-dev/pandas/issues/40226", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return isinstance(self.values, Categorical) @@ -252,7 +253,7 @@ def make_block_same_class( "already been cast to DatetimeArray and TimedeltaArray, " "respectively.", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) values = new_values @@ -1564,7 +1565,7 @@ def fillna( "(usually object) instead of raising, matching the " "behavior of other dtypes.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) raise else: diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index c1d0ab730fe7e..6aad8dbd940d4 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -5,6 +5,7 @@ from __future__ import annotations from collections import abc +import inspect from typing import ( TYPE_CHECKING, Any, @@ -844,7 +845,7 @@ def to_arrays( "To retain the old behavior, pass as a dictionary " "DataFrame({col: categorical, ..})", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if columns is None: columns = default_index(len(data)) diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 435992f7d5cff..4e84b013b2a11 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import itertools from typing import ( Any, @@ -909,7 +910,7 @@ def __init__( "will assume that a DatetimeTZBlock with block.ndim==2 " "has block.values.ndim == 2.", DeprecationWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # error: Incompatible types in assignment (expression has type @@ -1248,7 +1249,7 @@ def insert(self, loc: int, item: Hashable, value: ArrayLike) -> None: "Consider joining all columns at once using pd.concat(axis=1) " "instead. To get a de-fragmented frame, use `newframe = frame.copy()`", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) def _insert_update_mgr_locs(self, loc) -> None: @@ -1707,7 +1708,7 @@ def __init__( "The `fastpath` keyword is deprecated and will be removed " "in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.axes = [axis] diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index e9fefd9268870..dde4d07b7915c 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -5,6 +5,7 @@ """ from __future__ import annotations +import inspect import operator from typing import TYPE_CHECKING import warnings @@ -301,7 +302,7 @@ def to_series(right): "Do `left, right = left.align(right, axis=1, copy=False)` " "before e.g. `left == right`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) left, right = left.align( diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 54b6b32ff1a68..e3d81e01ac94c 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -2,6 +2,7 @@ import copy from datetime import timedelta +import inspect from textwrap import dedent from typing import ( TYPE_CHECKING, @@ -549,7 +550,7 @@ def pad(self, limit=None): "pad is deprecated and will be removed in a future version. " "Use ffill instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.ffill(limit=limit) @@ -722,7 +723,7 @@ def backfill(self, limit=None): "backfill is deprecated and will be removed in a future version. " "Use bfill instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.bfill(limit=limit) diff --git a/pandas/core/reshape/concat.py b/pandas/core/reshape/concat.py index 5328c7995ea6f..3d9e4f0c69c62 100644 --- a/pandas/core/reshape/concat.py +++ b/pandas/core/reshape/concat.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections import abc +import inspect from typing import ( TYPE_CHECKING, Callable, @@ -552,7 +553,7 @@ def __init__( "Passing non boolean values for sort is deprecated and " "will error in a future version!", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.sort = sort diff --git a/pandas/core/reshape/melt.py b/pandas/core/reshape/melt.py index 5de9c8e2f4108..73f6aff82f330 100644 --- a/pandas/core/reshape/melt.py +++ b/pandas/core/reshape/melt.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import re from typing import TYPE_CHECKING import warnings @@ -59,7 +60,7 @@ def melt( "In the future this will raise an error, please set the 'value_name' " "parameter of DataFrame.melt to a unique name.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if id_vars is not None: diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index c7744945ad4af..f3f4568d1a4d3 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -7,6 +7,7 @@ import datetime from functools import partial import hashlib +import inspect import string from typing import ( TYPE_CHECKING, @@ -678,7 +679,9 @@ def __init__( ) # stacklevel chosen to be correct when this is reached via pd.merge # (and not DataFrame.join) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) self._validate_specification() @@ -1208,7 +1211,7 @@ def _maybe_coerce_merge_keys(self) -> None: "columns where the float values " "are not equal to their int representation.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) continue @@ -1221,7 +1224,7 @@ def _maybe_coerce_merge_keys(self) -> None: "columns where the float values " "are not equal to their int representation.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) continue @@ -2371,7 +2374,7 @@ def _items_overlap_with_suffix( "unexpected results. Provide 'suffixes' as a tuple instead. In the " "future a 'TypeError' will be raised.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) to_rename = left.intersection(right) @@ -2421,7 +2424,7 @@ def renamer(x, suffix): f"Passing 'suffixes' which cause duplicate columns {set(dups)} in the " f"result is deprecated and will raise a MergeError in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return llabels, rlabels diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py index 82e4a91f5e935..2d5e0ba157b70 100644 --- a/pandas/core/reshape/reshape.py +++ b/pandas/core/reshape/reshape.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import itertools from typing import TYPE_CHECKING import warnings @@ -128,7 +129,7 @@ def __init__(self, index: MultiIndex, level=-1, constructor=None) -> None: f"The following operation may generate {num_cells} cells " f"in the resulting pandas object.", PerformanceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self._make_selectors() diff --git a/pandas/core/series.py b/pandas/core/series.py index 206fcbe05d006..6f3769b53ad26 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect from textwrap import dedent from typing import ( IO, @@ -389,7 +390,7 @@ def __init__( "of 'float64' in a future version. Specify a dtype explicitly " "to silence this warning.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # uncomment the line below when removing the FutureWarning # dtype = np.dtype(object) @@ -916,7 +917,7 @@ def take(self, indices, axis=0, is_copy=None, **kwargs) -> Series: "is_copy is deprecated and will be removed in a future version. " "'take' always returns a copy, so there is no need to specify this.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) nv.validate_take((), kwargs) @@ -1047,7 +1048,9 @@ def _get_values_tuple(self, key: tuple): # see tests.series.timeseries.test_mpl_compat_hack # the asarray is needed to avoid returning a 2D DatetimeArray result = np.asarray(self._values[key]) - deprecate_ndim_indexing(result, stacklevel=find_stack_level()) + deprecate_ndim_indexing( + result, stacklevel=find_stack_level(inspect.currentframe()) + ) return result if not isinstance(self.index, MultiIndex): @@ -1111,7 +1114,7 @@ def __setitem__(self, key, value) -> None: "Series. Use `series.iloc[an_int] = val` to treat the " "key as positional.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # can't use _mgr.setitem_inplace yet bc could have *both* # KeyError and then ValueError, xref GH#45070 @@ -1797,7 +1800,7 @@ def iteritems(self) -> Iterable[tuple[Hashable, Any]]: "iteritems is deprecated and will be removed in a future version. " "Use .items instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.items() @@ -1880,7 +1883,7 @@ def to_frame(self, name: Hashable = lib.no_default) -> DataFrame: "the future `None` will be used as the name of the resulting " "DataFrame column.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) name = lib.no_default @@ -2018,7 +2021,7 @@ def groupby( "will be removed in a future version." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) else: squeeze = False @@ -2078,7 +2081,7 @@ def count(self, level=None): "deprecated and will be removed in a future version. Use groupby " "instead. ser.count(level=1) should use ser.groupby(level=1).count().", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if not isinstance(self.index, MultiIndex): raise ValueError("Series.count level is only valid with a MultiIndex") @@ -3076,7 +3079,7 @@ def append( "and will be removed from pandas in a future version. " "Use pandas.concat instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._append(to_append, ignore_index, verify_integrity) @@ -4733,7 +4736,7 @@ def _reduce( f"Calling Series.{name} with {kwd_name}={numeric_only} and " f"dtype {self.dtype} will raise a TypeError in the future", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) raise NotImplementedError( f"Series.{name} does not implement {kwd_name}." @@ -5611,7 +5614,7 @@ def between(self, left, right, inclusive="both") -> Series: "Boolean inputs to the `inclusive` argument are deprecated in " "favour of `both` or `neither`.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if inclusive: inclusive = "both" diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index d50daad9a22b1..b66660f315df1 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -2,6 +2,7 @@ import codecs from functools import wraps +import inspect import re from typing import ( TYPE_CHECKING, @@ -242,7 +243,7 @@ def __iter__(self): warnings.warn( "Columnar iteration over characters will be deprecated in future releases.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) i = 0 g = self.get(i) @@ -1244,7 +1245,7 @@ def contains(self, pat, case=True, flags=0, na=None, regex=True): "This pattern is interpreted as a regular expression, and has " "match groups. To actually get the groups, use str.extract.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) result = self._data.array._str_contains(pat, case, flags, na, regex) @@ -1456,7 +1457,11 @@ def replace( " In addition, single character regular expressions will " "*not* be treated as literal strings when regex=True." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, + FutureWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) # Check whether repl is valid (GH 13438, GH 15055) if not (isinstance(repl, str) or callable(repl)): diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 7ec4bc1016a9d..388f751d9cc57 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -3,6 +3,7 @@ from collections import abc from datetime import datetime from functools import partial +import inspect from itertools import islice from typing import ( TYPE_CHECKING, @@ -1284,7 +1285,7 @@ def to_time(arg, format=None, infer_time_format=False, errors="raise"): "`to_time` has been moved, should be imported from pandas.core.tools.times. " "This alias will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) from pandas.core.tools.times import to_time diff --git a/pandas/core/window/common.py b/pandas/core/window/common.py index e31b5c60a37ee..29b7558f40353 100644 --- a/pandas/core/window/common.py +++ b/pandas/core/window/common.py @@ -2,6 +2,7 @@ from __future__ import annotations from collections import defaultdict +import inspect from typing import cast import warnings @@ -203,5 +204,5 @@ def maybe_warn_args_and_kwargs(cls, kernel: str, args, kwargs) -> None: "no impact on the result and is deprecated. This will " "raise a TypeError in a future version of pandas.", category=FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/pandas/core/window/ewm.py b/pandas/core/window/ewm.py index 020ca71050015..32559d0d88bcf 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -2,6 +2,7 @@ import datetime from functools import partial +import inspect from textwrap import dedent from typing import ( TYPE_CHECKING, @@ -391,7 +392,7 @@ def __init__( "into times instead." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # self.times cannot be str anymore self.times = cast("Series", self._selected_obj[self.times]) @@ -683,7 +684,7 @@ def vol(self, bias: bool = False, *args, **kwargs): "Use std instead." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.std(bias, *args, **kwargs) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index c92c448304de2..3fc48b121419a 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -171,7 +171,7 @@ def win_type(self): "win_type will no longer return 'freq' in a future version. " "Check the type of self.window instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return "freq" return self._win_type @@ -181,7 +181,7 @@ def is_datetimelike(self) -> bool: warnings.warn( "is_datetimelike is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._win_freq_i8 is not None @@ -189,7 +189,7 @@ def validate(self) -> None: warnings.warn( "validate is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._validate() @@ -549,7 +549,7 @@ def hfunc(values: ArrayLike) -> ArrayLike: "Select only valid columns before calling the operation. " f"Dropped columns were {dropped}", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self._resolve_output(df, obj) @@ -1967,7 +1967,7 @@ def count(self, numeric_only: bool = False): "Specify min_periods=0 instead." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.min_periods = 0 result = super().count() diff --git a/pandas/io/clipboard/__init__.py b/pandas/io/clipboard/__init__.py index 28751fd531ffb..03599497f8d03 100644 --- a/pandas/io/clipboard/__init__.py +++ b/pandas/io/clipboard/__init__.py @@ -40,6 +40,8 @@ Pyperclip into running them with whatever permissions the Python process has. """ +import inspect + __version__ = "1.7.0" @@ -273,12 +275,12 @@ def copy_dev_clipboard(text): warnings.warn( "Pyperclip cannot copy a blank string to the clipboard on Cygwin. " "This is effectively a no-op.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if "\r" in text: warnings.warn( "Pyperclip cannot handle \\r characters on Cygwin.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) with open("/dev/clipboard", "wt") as fd: @@ -524,7 +526,7 @@ def determine_clipboard(): warnings.warn( "Pyperclip's support for Cygwin is not perfect, " "see https://github.com/asweigart/pyperclip/issues/55", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return init_dev_clipboard_clipboard() diff --git a/pandas/io/clipboards.py b/pandas/io/clipboards.py index a3e778e552439..7cf01affd5a19 100644 --- a/pandas/io/clipboards.py +++ b/pandas/io/clipboards.py @@ -1,6 +1,7 @@ """ io on the clipboard """ from __future__ import annotations +import inspect from io import StringIO import warnings @@ -82,7 +83,7 @@ def read_clipboard(sep: str = r"\s+", **kwargs): # pragma: no cover elif len(sep) > 1 and kwargs.get("engine") == "c": warnings.warn( "read_clipboard with regex separator does not work properly with c engine.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return read_csv(StringIO(text), sep=sep, **kwargs) @@ -139,12 +140,12 @@ def to_clipboard( except TypeError: warnings.warn( "to_clipboard in excel mode requires a single character separator.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif sep is not None: warnings.warn( "to_clipboard with excel=False ignores the sep argument.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if isinstance(obj, ABCDataFrame): diff --git a/pandas/io/common.py b/pandas/io/common.py index f31de63aa42a7..2fae19df13f8b 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -10,6 +10,7 @@ import dataclasses import functools import gzip +import inspect from io import ( BufferedIOBase, BytesIO, @@ -322,7 +323,7 @@ def _get_filepath_or_buffer( warnings.warn( "compression has no effect when passing a non-binary object as input.", RuntimeWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) compression_method = None @@ -338,7 +339,7 @@ def _get_filepath_or_buffer( warnings.warn( f"{compression} will not write the byte order mark for {encoding}", UnicodeWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # Use binary mode when converting path-like objects to file-like objects (fsspec) diff --git a/pandas/io/date_converters.py b/pandas/io/date_converters.py index 85e92da8c2a54..5885a3b9d14d7 100644 --- a/pandas/io/date_converters.py +++ b/pandas/io/date_converters.py @@ -1,6 +1,7 @@ """This module is designed for community supported date conversion functions""" from __future__ import annotations +import inspect import warnings import numpy as np @@ -22,7 +23,7 @@ def parse_date_time(date_col, time_col) -> npt.NDArray[np.object_]: Use pd.to_datetime(date_col + " " + time_col).to_pydatetime() instead to get a Numpy array. """, # noqa: E501 FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) date_col = _maybe_cast(date_col) time_col = _maybe_cast(time_col) @@ -42,7 +43,7 @@ def parse_date_fields(year_col, month_col, day_col) -> npt.NDArray[np.object_]: np.array([s.to_pydatetime() for s in ser]) instead to get a Numpy array. """, # noqa: E501 FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) year_col = _maybe_cast(year_col) @@ -69,7 +70,7 @@ def parse_all_fields( np.array([s.to_pydatetime() for s in ser]) instead to get a Numpy array. """, # noqa: E501 FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) year_col = _maybe_cast(year_col) @@ -95,7 +96,7 @@ def generic_parser(parse_func, *cols) -> np.ndarray: Use pd.to_datetime instead. """, FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) N = _check_columns(cols) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 44152f100d390..2fda6d239d85b 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -3,6 +3,7 @@ import abc import datetime from functools import partial +import inspect from io import BytesIO import os from textwrap import fill @@ -719,7 +720,7 @@ def parse( warnings.warn( "convert_float is deprecated and will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) validate_header_arg(header) @@ -1122,7 +1123,7 @@ def __new__( warnings.warn( "Use of **kwargs is deprecated, use engine_kwargs instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # only switch class if generic(ExcelWriter) @@ -1156,7 +1157,7 @@ def __new__( "deprecated and will also raise a warning, it can " "be globally set and the warning suppressed.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # for mypy @@ -1326,7 +1327,7 @@ def _deprecate(self, attr: str): f"{attr} is not part of the public API, usage can give in unexpected " "results and will be removed in a future version", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @property diff --git a/pandas/io/formats/css.py b/pandas/io/formats/css.py index cfc95bc9d9569..e86a1b0bcd635 100644 --- a/pandas/io/formats/css.py +++ b/pandas/io/formats/css.py @@ -3,6 +3,7 @@ """ from __future__ import annotations +import inspect import re from typing import ( Callable, @@ -50,7 +51,7 @@ def expand(self, prop, value: str) -> Generator[tuple[str, str], None, None]: warnings.warn( f'Could not expand "{prop}: {value}"', CSSWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return for key, idx in zip(self.SIDES, mapping): @@ -95,7 +96,7 @@ def expand(self, prop, value: str) -> Generator[tuple[str, str], None, None]: warnings.warn( f'Too many tokens provided to "{prop}" (expected 1-3)', CSSWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) # TODO: Can we use current color as initial value to comply with CSS standards? @@ -334,7 +335,7 @@ def _error(): warnings.warn( f"Unhandled size: {repr(in_val)}", CSSWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.size_to_pt("1!!default", conversions=conversions) @@ -407,5 +408,5 @@ def parse(self, declarations_str: str) -> Iterator[tuple[str, str]]: warnings.warn( f"Ill-formatted attribute: expected a colon in {repr(decl)}", CSSWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py index ce7f663dd5703..c4ddac088d901 100644 --- a/pandas/io/formats/excel.py +++ b/pandas/io/formats/excel.py @@ -7,6 +7,7 @@ lru_cache, reduce, ) +import inspect import itertools import re from typing import ( @@ -431,7 +432,7 @@ def color_to_excel(self, val: str | None) -> str | None: warnings.warn( f"Unhandled color format: {repr(val)}", CSSWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return None diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index df246ad30d806..0522e113d6525 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -6,6 +6,7 @@ from contextlib import contextmanager import copy from functools import partial +import inspect import operator from typing import ( Any, @@ -443,7 +444,7 @@ def render( warnings.warn( "this method is deprecated in favour of `Styler.to_html()`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if sparse_index is None: sparse_index = get_option("styler.sparse.index") @@ -2123,7 +2124,7 @@ def where( warnings.warn( "this method is deprecated in favour of `Styler.applymap()`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if other is None: @@ -2155,7 +2156,7 @@ def set_precision(self, precision: int) -> StylerRenderer: warnings.warn( "this method is deprecated in favour of `Styler.format(precision=..)`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.precision = precision return self.format(precision=precision, na_rep=self.na_rep) @@ -2667,7 +2668,7 @@ def set_na_rep(self, na_rep: str) -> StylerRenderer: warnings.warn( "this method is deprecated in favour of `Styler.format(na_rep=..)`", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.na_rep = na_rep return self.format(na_rep=na_rep, precision=self.precision) @@ -2721,7 +2722,7 @@ def hide_index( warnings.warn( 'this method is deprecated in favour of `Styler.hide(axis="index")`', FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.hide(axis="index", level=level, subset=subset, names=names) @@ -2774,7 +2775,7 @@ def hide_columns( warnings.warn( 'this method is deprecated in favour of `Styler.hide(axis="columns")`', FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return self.hide(axis="columns", level=level, subset=subset, names=names) @@ -3381,7 +3382,7 @@ def f(data: DataFrame, props: str) -> np.ndarray: warnings.warn( "`null_color` is deprecated: use `color` instead", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if color is None and null_color == lib.no_default: diff --git a/pandas/io/json/_table_schema.py b/pandas/io/json/_table_schema.py index 0d6cab20f2a59..7c323992d11a0 100644 --- a/pandas/io/json/_table_schema.py +++ b/pandas/io/json/_table_schema.py @@ -5,6 +5,7 @@ """ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, Any, @@ -103,12 +104,12 @@ def set_default_names(data): if len(nms) == 1 and data.index.name == "index": warnings.warn( "Index name of 'index' is not round-trippable.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) elif len(nms) > 1 and any(x.startswith("level_") for x in nms): warnings.warn( "Index names beginning with 'level_' are not round-trippable.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return data diff --git a/pandas/io/parsers/base_parser.py b/pandas/io/parsers/base_parser.py index 0e40e47bf7cb1..89bf903fea8dd 100644 --- a/pandas/io/parsers/base_parser.py +++ b/pandas/io/parsers/base_parser.py @@ -5,6 +5,7 @@ import csv import datetime from enum import Enum +import inspect import itertools from typing import ( TYPE_CHECKING, @@ -559,7 +560,7 @@ def _convert_to_ndarrays( f"for column {c} - only the converter will be used." ), ParserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) try: @@ -857,7 +858,7 @@ def _check_data_length( "Length of header or names does not match length of data. This leads " "to a loss of data with index_col=False.", ParserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) @overload diff --git a/pandas/io/parsers/c_parser_wrapper.py b/pandas/io/parsers/c_parser_wrapper.py index aec999e40b0f5..99051ec661413 100644 --- a/pandas/io/parsers/c_parser_wrapper.py +++ b/pandas/io/parsers/c_parser_wrapper.py @@ -1,6 +1,7 @@ from __future__ import annotations from collections import defaultdict +import inspect from io import TextIOWrapper from typing import ( TYPE_CHECKING, @@ -421,7 +422,11 @@ def _concatenate_chunks(chunks: list[dict[int, ArrayLike]]) -> dict: f"Specify dtype option on import or set low_memory=False." ] ) - warnings.warn(warning_message, DtypeWarning, stacklevel=find_stack_level()) + warnings.warn( + warning_message, + DtypeWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) return result diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index 7c03a81dbc0e6..ff8c21ab89f30 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -5,6 +5,7 @@ defaultdict, ) import csv +import inspect from io import StringIO import re import sys @@ -599,7 +600,7 @@ def _handle_usecols( "Defining usecols with out of bounds indices is deprecated " "and will raise a ParserError in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) col_indices = self.usecols diff --git a/pandas/io/parsers/readers.py b/pandas/io/parsers/readers.py index dc4556542d8e2..03a634cf07e26 100644 --- a/pandas/io/parsers/readers.py +++ b/pandas/io/parsers/readers.py @@ -5,6 +5,7 @@ from collections import abc import csv +import inspect import sys from textwrap import fill from typing import ( @@ -1609,7 +1610,7 @@ def _clean_options( "engine='python'." ), ParserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) index_col = options["index_col"] @@ -1628,7 +1629,11 @@ def _clean_options( f"The {arg} argument has been deprecated and will be " f"removed in a future version. {depr_default.msg}\n\n" ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, + FutureWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) else: result[arg] = parser_default @@ -2203,7 +2208,9 @@ def _merge_with_dialect_properties( if conflict_msgs: warnings.warn( - "\n\n".join(conflict_msgs), ParserWarning, stacklevel=find_stack_level() + "\n\n".join(conflict_msgs), + ParserWarning, + stacklevel=find_stack_level(inspect.currentframe()), ) kwds[param] = dialect_val return kwds diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 855d97733ca06..96ba6b2e84cf3 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -10,6 +10,7 @@ date, tzinfo, ) +import inspect import itertools import os import re @@ -686,7 +687,7 @@ def iteritems(self): "iteritems is deprecated and will be removed in a future version. " "Use .items instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) yield from self.items() @@ -2195,7 +2196,9 @@ def update_info(self, info) -> None: if key in ["freq", "index_name"]: ws = attribute_conflict_doc % (key, existing_value, value) warnings.warn( - ws, AttributeConflictWarning, stacklevel=find_stack_level() + ws, + AttributeConflictWarning, + stacklevel=find_stack_level(inspect.currentframe()), ) # reset @@ -3093,7 +3096,11 @@ def write_array( pass else: ws = performance_doc % (inferred_type, key, items) - warnings.warn(ws, PerformanceWarning, stacklevel=find_stack_level()) + warnings.warn( + ws, + PerformanceWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) vlarr = self._handle.create_vlarray(self.group, key, _tables().ObjectAtom()) vlarr.append(value) @@ -3541,7 +3548,7 @@ def validate_version(self, where=None) -> None: warnings.warn( ws, IncompatibilityWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) def validate_min_itemsize(self, min_itemsize) -> None: diff --git a/pandas/io/sas/sas_xport.py b/pandas/io/sas/sas_xport.py index c188e8d1b03c3..648c58dee6600 100644 --- a/pandas/io/sas/sas_xport.py +++ b/pandas/io/sas/sas_xport.py @@ -11,6 +11,7 @@ from collections import abc from datetime import datetime +import inspect import struct import warnings @@ -415,7 +416,7 @@ def _record_count(self) -> int: if total_records_length % 80 != 0: warnings.warn( "xport file may be corrupted.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if self.record_length > 80: diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 82a20c080c1d3..ee6564d103147 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -12,6 +12,7 @@ time, ) from functools import partial +import inspect import re from typing import ( TYPE_CHECKING, @@ -761,7 +762,7 @@ def pandasSQL_builder(con, schema: str | None = None) -> SQLDatabase | SQLiteDat "database string URI or sqlite3 DBAPI2 connection. " "Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return SQLiteDatabase(con) @@ -1194,7 +1195,7 @@ def _sqlalchemy_type(self, col): "the 'timedelta' type is not supported, and will be " "written as integer values (ns frequency) to the database.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return BigInteger elif col_type == "floating": @@ -1658,7 +1659,7 @@ def check_case_sensitive( warnings.warn( msg, UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) def to_sql( @@ -1967,7 +1968,7 @@ def _sql_type_name(self, col): "the 'timedelta' type is not supported, and will be " "written as integer values (ns frequency) to the database.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) col_type = "integer" diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 201b6500c22b7..80e7f54d828b5 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -13,6 +13,7 @@ from collections import abc import datetime +import inspect from io import BytesIO import os import struct @@ -351,7 +352,7 @@ def convert_delta_safe(base, deltas, unit) -> Series: warnings.warn( "Encountered %tC format. Leaving in Stata Internal Format.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) conv_dates = Series(dates, dtype=object) if has_bad_values: @@ -468,7 +469,7 @@ def g(x: datetime.datetime) -> int: elif fmt in ["%tC", "tC"]: warnings.warn( "Stata Internal Format tC not supported.", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) conv_dates = dates elif fmt in ["%td", "td"]: @@ -652,7 +653,7 @@ def _cast_to_stata_types(data: DataFrame) -> DataFrame: warnings.warn( ws, PossiblePrecisionLoss, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return data @@ -708,7 +709,7 @@ def _prepare_value_labels(self): warnings.warn( value_label_mismatch_doc.format(self.labname), ValueLabelTypeMismatch, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) category = category.encode(self._encoding) offsets.append(self.text_len) @@ -1521,7 +1522,7 @@ def _decode(self, s: bytes) -> str: warnings.warn( msg, UnicodeWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return s.decode("latin-1") @@ -1920,7 +1921,7 @@ def _do_convert_categoricals( warnings.warn( categorical_conversion_warning, CategoricalConversionWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) initial_categories = None cat_data = Categorical( @@ -2503,7 +2504,7 @@ def _check_column_names(self, data: DataFrame) -> DataFrame: warnings.warn( ws, InvalidColumnName, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self._converted_names = converted_names @@ -2671,7 +2672,7 @@ def write_file(self) -> None: f"This save was not successful but {self._fname} could not " "be deleted. This file is not valid.", ResourceWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) raise exc diff --git a/pandas/plotting/_matplotlib/boxplot.py b/pandas/plotting/_matplotlib/boxplot.py index 6789485f2b9eb..d85495b70e6c3 100644 --- a/pandas/plotting/_matplotlib/boxplot.py +++ b/pandas/plotting/_matplotlib/boxplot.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect from typing import ( TYPE_CHECKING, Literal, @@ -92,7 +93,7 @@ def _validate_color_args(self): warnings.warn( "'color' and 'colormap' cannot be used " "simultaneously. Using 'color'", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.color = self.kwds.pop("color") diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 1909a8168ddd0..7d8c7da6dd9aa 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -4,6 +4,7 @@ ABC, abstractmethod, ) +import inspect from typing import ( TYPE_CHECKING, Hashable, @@ -396,7 +397,7 @@ def _validate_color_args(self): ) and self.colormap is not None: warnings.warn( "'color' and 'colormap' cannot be used simultaneously. Using 'color'", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if "color" in self.kwds and self.style is not None: diff --git a/pandas/plotting/_matplotlib/style.py b/pandas/plotting/_matplotlib/style.py index f7668f7b8ff29..2f29aafbdf5cf 100644 --- a/pandas/plotting/_matplotlib/style.py +++ b/pandas/plotting/_matplotlib/style.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import itertools from typing import ( TYPE_CHECKING, @@ -124,7 +125,7 @@ def _derive_colors( if colormap is not None: warnings.warn( "'color' and 'colormap' cannot be used simultaneously. Using 'color'", - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return _get_colors_from_color(color) else: diff --git a/pandas/plotting/_matplotlib/tools.py b/pandas/plotting/_matplotlib/tools.py index 1925dd8c4023c..8f0ea70ab4124 100644 --- a/pandas/plotting/_matplotlib/tools.py +++ b/pandas/plotting/_matplotlib/tools.py @@ -1,6 +1,7 @@ # being a bit too dynamic from __future__ import annotations +import inspect from math import ceil from typing import ( TYPE_CHECKING, @@ -233,14 +234,14 @@ def create_subplots( warnings.warn( "When passing multiple axes, layout keyword is ignored.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if sharex or sharey: warnings.warn( "When passing multiple axes, sharex and sharey " "are ignored. These settings must be specified when creating axes.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) if ax.size == naxes: fig = ax.flat[0].get_figure() @@ -263,7 +264,7 @@ def create_subplots( "To output multiple subplots, the figure containing " "the passed axes is being cleared.", UserWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) fig.clear() diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index 9f553686ca829..3edabc7c089e1 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect import warnings import numpy as np @@ -116,7 +117,7 @@ def get_offset(name: str) -> BaseOffset: "get_offset is deprecated and will be removed in a future version, " "use to_offset instead.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return _get_offset(name) @@ -234,7 +235,7 @@ def __init__(self, index, warn: bool = True) -> None: "warn is deprecated (and never implemented) and " "will be removed in a future version.", FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) self.warn = warn diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index f8359edaa8d44..86c945f1321f5 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -312,7 +312,7 @@ def wrapper(*args, **kwargs): warnings.warn( msg.format(arguments=arguments), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) return func(*args, **kwargs) diff --git a/pandas/util/_exceptions.py b/pandas/util/_exceptions.py index c718451fbf621..95456f1d22148 100644 --- a/pandas/util/_exceptions.py +++ b/pandas/util/_exceptions.py @@ -25,7 +25,11 @@ def rewrite_exception(old_name: str, new_name: str) -> Iterator[None]: raise -def find_stack_level() -> int: +import functools + + +@functools.lru_cache +def find_stack_level(frame) -> int: """ Find the first place in the stack that is not inside pandas (tests notwithstanding). @@ -37,7 +41,6 @@ def find_stack_level() -> int: test_dir = os.path.join(pkg_dir, "tests") # https://stackoverflow.com/questions/17407119/python-inspect-stack-is-slow - frame = inspect.currentframe() n = 0 while frame: fname = inspect.getfile(frame) diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index a4a9ebfbf4126..7e938e4648e97 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -4,6 +4,7 @@ """ from __future__ import annotations +import inspect from typing import ( Any, Iterable, @@ -355,7 +356,9 @@ def validate_axis_style_args( "positional arguments for 'index' or 'columns' will raise " "a 'TypeError'." ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warnings.warn( + msg, FutureWarning, stacklevel=find_stack_level(inspect.currentframe()) + ) out[data._get_axis_name(0)] = args[0] out[data._get_axis_name(1)] = args[1] else: diff --git a/pandas/util/testing.py b/pandas/util/testing.py index db9bfc274cd78..5585ea0b58628 100644 --- a/pandas/util/testing.py +++ b/pandas/util/testing.py @@ -1,3 +1,4 @@ +import inspect import warnings from pandas.util._exceptions import find_stack_level @@ -10,5 +11,5 @@ "public API at pandas.testing instead." ), FutureWarning, - stacklevel=find_stack_level(), + stacklevel=find_stack_level(inspect.currentframe()), ) diff --git a/scripts/list_future_warnings.sh b/scripts/list_future_warnings.sh index a75aea905a4c8..dc3d0b59b618b 100755 --- a/scripts/list_future_warnings.sh +++ b/scripts/list_future_warnings.sh @@ -6,7 +6,7 @@ # This is useful to detect features that have been deprecated, and should be # removed from the code. For example, if a line of code contains: # -# warning.warn('Method deprecated', FutureWarning, stacklevel=find_stack_level()) +# warning.warn('Method deprecated', FutureWarning, stacklevel=find_stack_level(inspect.currentframe())) # # Which is released in Pandas 0.20.0, then it is expected that the method # is removed before releasing Pandas 0.24.0, including the warning. If it From feb36cca2fff79fffd619dd7827c05eadf6d17c7 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 15:26:03 +0200 Subject: [PATCH 08/18] fixup import in __init__ --- pandas/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/__init__.py b/pandas/__init__.py index 75409dc7e8e53..2eec6ca6901b1 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -190,10 +190,9 @@ def __dir__() -> list[str]: def __getattr__(name): import warnings + from pandas.util._exceptions import find_stack_level if name in __deprecated_num_index_names: - from pandas.util._exceptions import find_stack_level - warnings.warn( f"pandas.{name} is deprecated " "and will be removed from pandas in a future version. " From ed1e6a7187aede08da6e5d2d19f9eab50d2bd4c5 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 15:58:30 +0200 Subject: [PATCH 09/18] add missing imports to pyx files --- pandas/_libs/interval.pyx | 1 + pandas/_libs/lib.pyx | 2 ++ pandas/_libs/tslib.pyx | 2 ++ pandas/_libs/tslibs/conversion.pyx | 2 ++ pandas/_libs/tslibs/nattype.pyx | 1 + pandas/_libs/tslibs/offsets.pyx | 1 + pandas/_libs/tslibs/period.pyx | 1 + pandas/_libs/tslibs/timedeltas.pyx | 1 + pandas/_libs/tslibs/timestamps.pyx | 3 +++ 9 files changed, 14 insertions(+) diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index fc6f770e819d8..87031eb6c6533 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -1,3 +1,4 @@ +import inspect import numbers from operator import ( le, diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 6be1e38e63ed6..8e4b23f32f48c 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -1,6 +1,7 @@ from collections import abc from decimal import Decimal from enum import Enum +import inspect from typing import Literal import warnings @@ -29,6 +30,7 @@ from cython cimport ( Py_ssize_t, floating, ) + from pandas.util._exceptions import find_stack_level import_datetime() diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 9056f21f8070f..04105b370015e 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1,3 +1,4 @@ +import inspect import warnings cimport cython @@ -8,6 +9,7 @@ from cpython.datetime cimport ( import_datetime, tzinfo, ) + from pandas.util._exceptions import find_stack_level # import datetime C API diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 938e563837d3f..32b105fb1c8ec 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -1,3 +1,5 @@ +cimport inspect + cimport cython import warnings diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 8422c9421dc57..fb6d64eafe8fc 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -1,3 +1,4 @@ +import inspect import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index abde6612de14a..05a36e123821d 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1,3 +1,4 @@ +import inspect import operator import re import time diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 48a868e9d7bd2..d2d4838bfafc0 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,3 +1,4 @@ +import inspect import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index be008891c4455..f53d4ccf2d555 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,4 +1,5 @@ import collections +import inspect import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 6a1862513668f..2655c25ed0893 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -6,6 +6,7 @@ construction requirements, we need to do object instantiation in python (see Timestamp class below). This will serve as a C extension type that shadows the python class, where we do any heavy lifting. """ +import inspect import warnings cimport cython @@ -47,7 +48,9 @@ import_datetime() from pandas._libs.tslibs cimport ccalendar from pandas._libs.tslibs.base cimport ABCTimestamp + from pandas.util._exceptions import find_stack_level + from pandas._libs.tslibs.conversion cimport ( _TSObject, convert_datetime_to_tsobject, From d20c05c321a547eb0edad5fb79c79b10e98898e2 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 16:06:29 +0200 Subject: [PATCH 10/18] add missing import --- .pre-commit-config.yaml | 3 ++- pandas/_libs/parsers.pyx | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db964c1f4d512..8563ceb415a94 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -147,7 +147,8 @@ repos: # Check for deprecated messages without sphinx directive |(DEPRECATED|DEPRECATE|Deprecated)(:|,|\.) - # Check for ``stacklevel=5`` instead of ``stacklevel=find_stack_level(inspect.currentframe())`` + # Check for e.g. ``stacklevel=5`` instead of + # ``stacklevel=find_stack_level(inspect.currentframe())`` |stacklevel=\d+ types_or: [python, cython, rst] - id: cython-casting diff --git a/pandas/_libs/parsers.pyx b/pandas/_libs/parsers.pyx index 6dfce71703c6a..e8b7160af9b2c 100644 --- a/pandas/_libs/parsers.pyx +++ b/pandas/_libs/parsers.pyx @@ -8,6 +8,7 @@ from csv import ( QUOTE_NONNUMERIC, ) from errno import ENOENT +import inspect import sys import time import warnings From 0e40eb7ecf92ba08c4e672d614ab25cecd388bbe Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 16:08:54 +0200 Subject: [PATCH 11/18] fixup import in conversion --- pandas/_libs/tslibs/conversion.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 32b105fb1c8ec..b25095ead790b 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -1,4 +1,4 @@ -cimport inspect +import inspect cimport cython From 0f7400bddb4a1d7e871231ca11edc648042c85c7 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 16:34:41 +0200 Subject: [PATCH 12/18] revert some __init__ changes --- .pre-commit-config.yaml | 10 ++- pandas/__init__.py | 194 ++++++++++++++++++++-------------------- 2 files changed, 103 insertions(+), 101 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8563ceb415a94..4fcdf551012c7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -146,11 +146,13 @@ repos: # Check for deprecated messages without sphinx directive |(DEPRECATED|DEPRECATE|Deprecated)(:|,|\.) - - # Check for e.g. ``stacklevel=5`` instead of - # ``stacklevel=find_stack_level(inspect.currentframe())`` - |stacklevel=\d+ types_or: [python, cython, rst] + - id: stacklevel + name: Use find_stack_level instead of setting stacklevel manually + language: pygrep + entry: 'stacklevel=\d+' + types_or: [python, cython, rst] + exclude: pandas/__init__\.py - id: cython-casting name: Check Cython casting is `obj`, not ` obj` language: pygrep diff --git a/pandas/__init__.py b/pandas/__init__.py index 2eec6ca6901b1..eb5ce71141f46 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -1,7 +1,5 @@ from __future__ import annotations -import inspect - __docformat__ = "restructuredtext" # Let users know if they're missing any of our hard dependencies @@ -24,11 +22,7 @@ from pandas.compat import is_numpy_dev as _is_numpy_dev # pyright: ignore # noqa:F401 try: - from pandas._libs import ( - hashtable as _hashtable, - lib as _lib, - tslib as _tslib, - ) + from pandas._libs import hashtable as _hashtable, lib as _lib, tslib as _tslib except ImportError as _err: # pragma: no cover _module = _err.name raise ImportError( @@ -40,137 +34,148 @@ del _tslib, _lib, _hashtable from pandas._config import ( - describe_option, get_option, + set_option, + reset_option, + describe_option, option_context, options, - reset_option, - set_option, ) -from pandas.util._print_versions import show_versions -from pandas.util._tester import test - -from pandas import ( - api, - arrays, - errors, - io, - plotting, - tseries, -) -from pandas import testing # noqa:PDF015 +# let init-time option registration happen +import pandas.core.config_init # pyright: ignore # noqa:F401 -# use the closest tagged version if possible -from pandas._version import get_versions -from pandas.core.api import ( # dtype; missing; indexes; tseries; conversion; misc - NA, - BooleanDtype, - Categorical, - CategoricalDtype, - CategoricalIndex, - DataFrame, - DateOffset, - DatetimeIndex, - DatetimeTZDtype, - Flags, - Float32Dtype, - Float64Dtype, - Grouper, - Index, - IndexSlice, +from pandas.core.api import ( + # dtype Int8Dtype, Int16Dtype, Int32Dtype, Int64Dtype, - Interval, - IntervalDtype, - IntervalIndex, - MultiIndex, - NamedAgg, - NaT, - Period, - PeriodDtype, - PeriodIndex, - RangeIndex, - Series, - StringDtype, - Timedelta, - TimedeltaIndex, - Timestamp, UInt8Dtype, UInt16Dtype, UInt32Dtype, UInt64Dtype, - array, - bdate_range, - date_range, - factorize, - interval_range, + Float32Dtype, + Float64Dtype, + CategoricalDtype, + PeriodDtype, + IntervalDtype, + DatetimeTZDtype, + StringDtype, + BooleanDtype, + # missing + NA, isna, isnull, notna, notnull, + # indexes + Index, + CategoricalIndex, + RangeIndex, + MultiIndex, + IntervalIndex, + TimedeltaIndex, + DatetimeIndex, + PeriodIndex, + IndexSlice, + # tseries + NaT, + Period, period_range, - set_eng_float_format, + Timedelta, timedelta_range, - to_datetime, + Timestamp, + date_range, + bdate_range, + Interval, + interval_range, + DateOffset, + # conversion to_numeric, + to_datetime, to_timedelta, + # misc + Flags, + Grouper, + factorize, unique, value_counts, + NamedAgg, + array, + Categorical, + set_eng_float_format, + Series, + DataFrame, ) + from pandas.core.arrays.sparse import SparseDtype + +from pandas.tseries.api import infer_freq +from pandas.tseries import offsets + from pandas.core.computation.api import eval -# let init-time option registration happen -import pandas.core.config_init # pyright: ignore # noqa:F401 from pandas.core.reshape.api import ( concat, - crosstab, - cut, - from_dummies, - get_dummies, lreshape, melt, + wide_to_long, merge, merge_asof, merge_ordered, + crosstab, pivot, pivot_table, + get_dummies, + from_dummies, + cut, qcut, - wide_to_long, ) -from pandas.io.api import ( # excel; parsers; pickle; pytables; sql; misc +from pandas import api, arrays, errors, io, plotting, tseries +from pandas import testing # noqa:PDF015 +from pandas.util._print_versions import show_versions + +from pandas.io.api import ( + # excel ExcelFile, ExcelWriter, + read_excel, + # parsers + read_csv, + read_fwf, + read_table, + # pickle + read_pickle, + to_pickle, + # pytables HDFStore, + read_hdf, + # sql + read_sql, + read_sql_query, + read_sql_table, + # misc read_clipboard, - read_csv, - read_excel, + read_parquet, + read_orc, read_feather, - read_fwf, read_gbq, - read_hdf, read_html, + read_xml, read_json, - read_orc, - read_parquet, - read_pickle, + read_stata, read_sas, read_spss, - read_sql, - read_sql_query, - read_sql_table, - read_stata, - read_table, - read_xml, - to_pickle, ) + from pandas.io.json import _json_normalize as json_normalize -from pandas.tseries import offsets -from pandas.tseries.api import infer_freq + +from pandas.util._tester import test + +# use the closest tagged version if possible +from pandas._version import get_versions v = get_versions() __version__ = v.get("closest-tag", v["version"]) @@ -190,7 +195,6 @@ def __dir__() -> list[str]: def __getattr__(name): import warnings - from pandas.util._exceptions import find_stack_level if name in __deprecated_num_index_names: warnings.warn( @@ -198,13 +202,9 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.Index with the appropriate dtype instead.", FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), - ) - from pandas.core.api import ( - Float64Index, - Int64Index, - UInt64Index, + stacklevel=2, ) + from pandas.core.api import Float64Index, Int64Index, UInt64Index return { "Float64Index": Float64Index, @@ -217,7 +217,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import from datetime module instead.", FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=2, ) from datetime import datetime as dt @@ -231,7 +231,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Import numpy directly instead.", FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=2, ) import numpy as np @@ -242,7 +242,7 @@ def __getattr__(name): f"The {name} class is removed from pandas. Accessing it from " "the top-level namespace will also be removed in the next version.", FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=2, ) return type(name, (), {}) @@ -254,7 +254,7 @@ def __getattr__(name): "and will be removed from pandas in a future version. " "Use pandas.arrays.SparseArray instead.", FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=2, ) from pandas.core.arrays.sparse import SparseArray as _SparseArray From 89b5f52d30bb53108b78b853f99f522062703fe2 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 8 Aug 2022 22:16:29 +0200 Subject: [PATCH 13/18] start n=1 --- pandas/tests/io/test_clipboard.py | 6 +++++- pandas/util/_exceptions.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pandas/tests/io/test_clipboard.py b/pandas/tests/io/test_clipboard.py index cb34cb6678a67..db85cb416145f 100644 --- a/pandas/tests/io/test_clipboard.py +++ b/pandas/tests/io/test_clipboard.py @@ -258,7 +258,11 @@ def test_round_trip_frame_string(self, df): # Two character separator is not supported in to_clipboard # Test that multi-character separators are not silently passed def test_excel_sep_warning(self, df): - with tm.assert_produces_warning(): + with tm.assert_produces_warning( + UserWarning, + match="to_clipboard in excel mode requires a single character separator.", + check_stacklevel=False, + ): df.to_clipboard(excel=True, sep=r"\t") # Separator is ignored when excel=False and should produce a warning diff --git a/pandas/util/_exceptions.py b/pandas/util/_exceptions.py index 95456f1d22148..3bdec220af25f 100644 --- a/pandas/util/_exceptions.py +++ b/pandas/util/_exceptions.py @@ -41,7 +41,7 @@ def find_stack_level(frame) -> int: test_dir = os.path.join(pkg_dir, "tests") # https://stackoverflow.com/questions/17407119/python-inspect-stack-is-slow - n = 0 + n = 1 while frame: fname = inspect.getfile(frame) if fname.startswith(pkg_dir) and not fname.startswith(test_dir): From 591b2bbf74fd070b05e2c106a176fc7cce8d6413 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Wed, 10 Aug 2022 14:10:16 +0200 Subject: [PATCH 14/18] temporarily dont check stacklevel in _check_plot_works --- .pre-commit-config.yaml | 6 --- pandas/compat/pickle_compat.py | 6 +-- pandas/core/internals/__init__.py | 3 +- pandas/tests/indexes/test_common.py | 1 + pandas/tests/io/parser/test_dialect.py | 11 ++++-- .../io/parser/test_python_parser_only.py | 5 ++- .../tests/plotting/frame/test_hist_box_by.py | 2 +- pandas/tests/plotting/test_boxplot_method.py | 2 +- pandas/tests/plotting/test_hist_method.py | 38 +++++++++---------- pandas/tests/plotting/test_misc.py | 2 +- 10 files changed, 37 insertions(+), 39 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4fcdf551012c7..dbddba57ef21c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -147,12 +147,6 @@ repos: # Check for deprecated messages without sphinx directive |(DEPRECATED|DEPRECATE|Deprecated)(:|,|\.) types_or: [python, cython, rst] - - id: stacklevel - name: Use find_stack_level instead of setting stacklevel manually - language: pygrep - entry: 'stacklevel=\d+' - types_or: [python, cython, rst] - exclude: pandas/__init__\.py - id: cython-casting name: Check Cython casting is `obj`, not ` obj` language: pygrep diff --git a/pandas/compat/pickle_compat.py b/pandas/compat/pickle_compat.py index 9e4492f5dbf89..c8db82500d0d6 100644 --- a/pandas/compat/pickle_compat.py +++ b/pandas/compat/pickle_compat.py @@ -5,7 +5,6 @@ import contextlib import copy -import inspect import io import pickle as pkl from typing import ( @@ -18,7 +17,6 @@ from pandas._libs.arrays import NDArrayBacked from pandas._libs.tslibs import BaseOffset -from pandas.util._exceptions import find_stack_level from pandas import Index from pandas.core.arrays import ( @@ -89,7 +87,7 @@ def __new__(cls) -> Series: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseSeries", new="Series"), FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=6, ) return Series(dtype=object) @@ -107,7 +105,7 @@ def __new__(cls) -> DataFrame: # type: ignore[misc] warnings.warn( _sparse_msg.format(cls="SparseDataFrame", new="DataFrame"), FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), + stacklevel=6, ) return DataFrame() diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index a4bd1f274066e..8c62576c2f2ca 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -1,5 +1,3 @@ -import inspect - from pandas.core.internals.api import make_block from pandas.core.internals.array_manager import ( ArrayManager, @@ -43,6 +41,7 @@ def __getattr__(name: str): + import inspect import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/tests/indexes/test_common.py b/pandas/tests/indexes/test_common.py index e7e971f957e48..40a107658231d 100644 --- a/pandas/tests/indexes/test_common.py +++ b/pandas/tests/indexes/test_common.py @@ -406,6 +406,7 @@ def test_astype_preserves_name(self, index, dtype): with tm.assert_produces_warning( warn, raise_on_extra_warnings=is_pyarrow_str, + check_stacklevel=False, ): result = index.astype(dtype) except (ValueError, TypeError, NotImplementedError, SystemError): diff --git a/pandas/tests/io/parser/test_dialect.py b/pandas/tests/io/parser/test_dialect.py index 3956967631ea8..458d4116558e4 100644 --- a/pandas/tests/io/parser/test_dialect.py +++ b/pandas/tests/io/parser/test_dialect.py @@ -146,6 +146,11 @@ def test_dialect_conflict_delimiter(all_parsers, custom_dialect, kwargs, warning data = "a:b\n1:2" with tm.with_csv_dialect(dialect_name, **dialect_kwargs): - with tm.assert_produces_warning(warning_klass): - result = parser.read_csv(StringIO(data), dialect=dialect_name, **kwargs) - tm.assert_frame_equal(result, expected) + result = parser.read_csv_check_warnings( + warning_klass, + "Conflicting values for 'delimiter'", + StringIO(data), + dialect=dialect_name, + **kwargs, + ) + tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/io/parser/test_python_parser_only.py b/pandas/tests/io/parser/test_python_parser_only.py index 84e0c8cbfdf88..6fbe274d732f5 100644 --- a/pandas/tests/io/parser/test_python_parser_only.py +++ b/pandas/tests/io/parser/test_python_parser_only.py @@ -424,8 +424,9 @@ def test_on_bad_lines_callable_not_expected_length(python_parser_only): """ bad_sio = StringIO(data) - with tm.assert_produces_warning(ParserWarning, match="Length of header or names"): - result = parser.read_csv(bad_sio, on_bad_lines=lambda x: x) + result = parser.read_csv_check_warnings( + ParserWarning, "Length of header or names", bad_sio, on_bad_lines=lambda x: x + ) expected = DataFrame({"a": [1, 2, 3], "b": [2, 3, 4]}) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/plotting/frame/test_hist_box_by.py b/pandas/tests/plotting/frame/test_hist_box_by.py index fe39c3d441396..e568016c858fd 100644 --- a/pandas/tests/plotting/frame/test_hist_box_by.py +++ b/pandas/tests/plotting/frame/test_hist_box_by.py @@ -164,7 +164,7 @@ def test_hist_plot_empty_list_string_tuple_by(self, by, column, hist_df): def test_hist_plot_layout_with_by(self, by, column, layout, axes_num, hist_df): # GH 15079 # _check_plot_works adds an ax so catch warning. see GH #13188 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( hist_df.plot.hist, column=column, by=by, layout=layout ) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 595af94030a85..ad6b1bbc353b8 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -77,7 +77,7 @@ def test_boxplot_legacy2(self): df = DataFrame(np.random.rand(10, 2), columns=["Col1", "Col2"]) df["X"] = Series(["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"]) df["Y"] = Series(["A"] * 10) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.boxplot, by="X") # When ax is supplied and required number of axes is 1, diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 0955e7808f3f6..9c11d589716fe 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -31,9 +31,9 @@ def test_hist_legacy(self, ts): _check_plot_works(ts.hist, grid=False) _check_plot_works(ts.hist, figsize=(8, 10)) # _check_plot_works adds an ax so catch warning. see GH #13188 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(ts.hist, by=ts.index.month) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(ts.hist, by=ts.index.month, bins=5) fig, ax = self.plt.subplots(1, 1) @@ -74,31 +74,31 @@ def test_hist_layout_with_by(self, hist_df): # _check_plot_works adds an `ax` kwarg to the method call # so we get a warning about an axis being cleared, even # though we don't explicing pass one, see GH #13188 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.gender, layout=(2, 1)) self._check_axes_shape(axes, axes_num=2, layout=(2, 1)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.gender, layout=(3, -1)) self._check_axes_shape(axes, axes_num=2, layout=(3, 1)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.category, layout=(4, 1)) self._check_axes_shape(axes, axes_num=4, layout=(4, 1)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.category, layout=(2, -1)) self._check_axes_shape(axes, axes_num=4, layout=(2, 2)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.category, layout=(3, -1)) self._check_axes_shape(axes, axes_num=4, layout=(3, 2)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.category, layout=(-1, 4)) self._check_axes_shape(axes, axes_num=4, layout=(1, 4)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.height.hist, by=df.classroom, layout=(2, 2)) self._check_axes_shape(axes, axes_num=3, layout=(2, 2)) @@ -235,7 +235,7 @@ class TestDataFramePlots(TestPlotBase): def test_hist_df_legacy(self, hist_df): from matplotlib.patches import Rectangle - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(hist_df.hist) # make sure layout is handled @@ -248,7 +248,7 @@ def test_hist_df_legacy(self, hist_df): dtype=np.int64, ) ) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.hist, grid=False) self._check_axes_shape(axes, axes_num=3, layout=(2, 2)) assert not axes[1, 1].get_visible() @@ -267,20 +267,20 @@ def test_hist_df_legacy(self, hist_df): dtype=np.int64, ) ) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.hist, layout=(4, 2)) self._check_axes_shape(axes, axes_num=6, layout=(4, 2)) # make sure sharex, sharey is handled - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.hist, sharex=True, sharey=True) # handle figsize arg - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.hist, figsize=(8, 10)) # check bins argument - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): _check_plot_works(df.hist, bins=5) # make sure xlabelsize and xrot are handled @@ -659,13 +659,13 @@ def test_grouped_hist_layout(self, hist_df): with pytest.raises(ValueError, match=msg): df.hist(column="height", by=df.category, layout=(-1, -1)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( df.hist, column="height", by=df.gender, layout=(2, 1) ) self._check_axes_shape(axes, axes_num=2, layout=(2, 1)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( df.hist, column="height", by=df.gender, layout=(2, -1) ) @@ -682,14 +682,14 @@ def test_grouped_hist_layout(self, hist_df): tm.close() # GH 6769 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( df.hist, column="height", by="classroom", layout=(2, 2) ) self._check_axes_shape(axes, axes_num=3, layout=(2, 2)) # without column - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(df.hist, by="classroom") self._check_axes_shape(axes, axes_num=3, layout=(2, 2)) diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index 95900e163ad9e..7dd9b78bab1cd 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -125,7 +125,7 @@ def test_scatter_matrix_axis(self, pass_axis): df[0] = (df[0] - 2) / 3 # we are plotting multiples on a sub-plot - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works( scatter_matrix, filterwarnings="always", From 1a68c9e5f9b5800ff753685c244e5c395669242f Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Fri, 12 Aug 2022 15:07:09 +0200 Subject: [PATCH 15/18] catch some more warnings --- pandas/tests/io/parser/dtypes/test_dtypes_basic.py | 2 +- pandas/tests/io/parser/test_python_parser_only.py | 5 +++-- pandas/tests/plotting/test_boxplot_method.py | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py index 4cb297872c5b6..420282b4242ff 100644 --- a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py +++ b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py @@ -103,7 +103,7 @@ def test_dtype_with_converters(all_parsers): 1.2,2.3""" # Dtype spec ignored if converted specified. - result = parser.read_csv( + result = parser.read_csv_check_warnings( ParserWarning, "Both a converter and dtype were specified for column a" "- only the converter will be used.", diff --git a/pandas/tests/io/parser/test_python_parser_only.py b/pandas/tests/io/parser/test_python_parser_only.py index 6fbe274d732f5..1d3392b124895 100644 --- a/pandas/tests/io/parser/test_python_parser_only.py +++ b/pandas/tests/io/parser/test_python_parser_only.py @@ -483,7 +483,8 @@ def test_header_int_do_not_infer_multiindex_names_on_different_line(python_parse # GH#46569 parser = python_parser_only data = StringIO("a\na,b\nc,d,e\nf,g,h") - with tm.assert_produces_warning(ParserWarning, match="Length of header"): - result = parser.read_csv(data, engine="python", index_col=False) + result = parser.read_csv_check_warnings( + ParserWarning, "Length of header", data, engine="python", index_col=False + ) expected = DataFrame({"a": ["a", "c", "f"]}) tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index ad6b1bbc353b8..ef2422997a7ca 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -330,7 +330,7 @@ def test_boxplot_group_xlabel_ylabel(self, vert): class TestDataFrameGroupByPlots(TestPlotBase): def test_boxplot_legacy1(self, hist_df): grouped = hist_df.groupby(by="gender") - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(grouped.boxplot, return_type="axes") self._check_axes_shape(list(axes.values), axes_num=2, layout=(1, 2)) axes = _check_plot_works(grouped.boxplot, subplots=False, return_type="axes") @@ -341,7 +341,7 @@ def test_boxplot_legacy2(self): tuples = zip(string.ascii_letters[:10], range(10)) df = DataFrame(np.random.rand(10, 3), index=MultiIndex.from_tuples(tuples)) grouped = df.groupby(level=1) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(grouped.boxplot, return_type="axes") self._check_axes_shape(list(axes.values), axes_num=10, layout=(4, 3)) @@ -352,7 +352,7 @@ def test_boxplot_legacy3(self): tuples = zip(string.ascii_letters[:10], range(10)) df = DataFrame(np.random.rand(10, 3), index=MultiIndex.from_tuples(tuples)) grouped = df.unstack(level=1).groupby(level=0, axis=1) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): axes = _check_plot_works(grouped.boxplot, return_type="axes") self._check_axes_shape(list(axes.values), axes_num=3, layout=(2, 2)) axes = _check_plot_works(grouped.boxplot, subplots=False, return_type="axes") From 1b676798e4fbe5595fbc5cad2f35193dcba6d04f Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Fri, 12 Aug 2022 17:10:47 +0200 Subject: [PATCH 16/18] dont check stacklevel in check_plot_works --- pandas/tests/plotting/test_boxplot_method.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index ef2422997a7ca..29493dbc801c2 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -437,7 +437,7 @@ def test_grouped_box_layout(self, hist_df): df.boxplot(column=["weight", "height"], by=df.gender, layout=(-1, -1)) # _check_plot_works adds an ax so catch warning. see GH #13188 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): box = _check_plot_works( df.groupby("gender").boxplot, column="height", return_type="dict" ) From 9c55b191deffd7cc1f25d4614fe2f113dd4626cc Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sat, 13 Aug 2022 19:13:41 +0200 Subject: [PATCH 17/18] fixup --- pandas/tests/io/parser/dtypes/test_dtypes_basic.py | 2 +- pandas/tests/plotting/test_boxplot_method.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py index 420282b4242ff..2c18d461cddf8 100644 --- a/pandas/tests/io/parser/dtypes/test_dtypes_basic.py +++ b/pandas/tests/io/parser/dtypes/test_dtypes_basic.py @@ -105,7 +105,7 @@ def test_dtype_with_converters(all_parsers): # Dtype spec ignored if converted specified. result = parser.read_csv_check_warnings( ParserWarning, - "Both a converter and dtype were specified for column a" + "Both a converter and dtype were specified for column a " "- only the converter will be used.", StringIO(data), dtype={"a": "i8"}, diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 29493dbc801c2..9a4381f62fd25 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -443,7 +443,7 @@ def test_grouped_box_layout(self, hist_df): ) self._check_axes_shape(self.plt.gcf().axes, axes_num=2, layout=(1, 2)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): box = _check_plot_works( df.groupby("category").boxplot, column="height", return_type="dict" ) @@ -473,7 +473,7 @@ def test_grouped_box_layout(self, hist_df): ) self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(2, 2)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): box = _check_plot_works( df.groupby("category").boxplot, column="height", @@ -481,7 +481,7 @@ def test_grouped_box_layout(self, hist_df): return_type="dict", ) self._check_axes_shape(self.plt.gcf().axes, axes_num=4, layout=(3, 2)) - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): box = _check_plot_works( df.groupby("category").boxplot, column="height", From 538c37a93c3820ec90949f064149322c6d45edfb Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sun, 14 Aug 2022 21:01:45 +0100 Subject: [PATCH 18/18] ignore stacklevel in check_plot_works --- pandas/tests/plotting/test_boxplot_method.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 9a4381f62fd25..9112d5cb3368f 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -450,7 +450,7 @@ def test_grouped_box_layout(self, hist_df): self._check_axes_shape(self.plt.gcf().axes, axes_num=4, layout=(2, 2)) # GH 6769 - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): box = _check_plot_works( df.groupby("classroom").boxplot, column="height", return_type="dict" )