|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +from warnings import warn |
| 4 | + |
| 5 | + |
| 6 | +def find_stacklevel() -> int: |
| 7 | + """Find the first place in the stack that is not inside narwhals. |
| 8 | +
|
| 9 | + Returns: |
| 10 | + Stacklevel. |
| 11 | +
|
| 12 | + Taken from: |
| 13 | + https://github.com/pandas-dev/pandas/blob/ab89c53f48df67709a533b6a95ce3d911871a0a8/pandas/util/_exceptions.py#L30-L51 |
| 14 | + """ |
| 15 | + import inspect |
| 16 | + from pathlib import Path |
| 17 | + |
| 18 | + import narwhals as nw |
| 19 | + |
| 20 | + pkg_dir = str(Path(nw.__file__).parent) |
| 21 | + |
| 22 | + # https://stackoverflow.com/questions/17407119/python-inspect-stack-is-slow |
| 23 | + frame = inspect.currentframe() |
| 24 | + n = 0 |
| 25 | + try: |
| 26 | + while frame: |
| 27 | + fname = inspect.getfile(frame) |
| 28 | + if fname.startswith(pkg_dir) or ( |
| 29 | + (qualname := getattr(frame.f_code, "co_qualname", None)) |
| 30 | + # ignore @singledispatch wrappers |
| 31 | + and qualname.startswith("singledispatch.") |
| 32 | + ): |
| 33 | + frame = frame.f_back |
| 34 | + n += 1 |
| 35 | + else: # pragma: no cover |
| 36 | + break |
| 37 | + else: # pragma: no cover |
| 38 | + pass |
| 39 | + finally: |
| 40 | + # https://docs.python.org/3/library/inspect.html |
| 41 | + # > Though the cycle detector will catch these, destruction of the frames |
| 42 | + # > (and local variables) can be made deterministic by removing the cycle |
| 43 | + # > in a finally clause. |
| 44 | + del frame |
| 45 | + return n |
| 46 | + |
| 47 | + |
| 48 | +def issue_deprecation_warning(message: str, _version: str) -> None: # pragma: no cover |
| 49 | + """Issue a deprecation warning. |
| 50 | +
|
| 51 | + Arguments: |
| 52 | + message: The message associated with the warning. |
| 53 | + _version: Narwhals version when the warning was introduced. Just used for internal |
| 54 | + bookkeeping. |
| 55 | + """ |
| 56 | + warn(message=message, category=DeprecationWarning, stacklevel=find_stacklevel()) |
| 57 | + |
| 58 | + |
| 59 | +def issue_warning(message: str, category: type[Warning]) -> None: |
| 60 | + warn(message=message, category=category, stacklevel=find_stacklevel()) |
0 commit comments