"""Deprecation utilities for SQLSpec.
Provides decorators and warning functions for marking deprecated functionality.
Used to communicate API changes and migration paths to users.
"""
import functools
import inspect
import types
from collections.abc import Callable
from typing import Generic, Literal, cast
from warnings import warn
from typing_extensions import ParamSpec, TypeVar
__all__ = ("deprecated", "warn_deprecation")
T = TypeVar("T")
P = ParamSpec("P")
DeprecatedKind = Literal["function", "method", "classmethod", "attribute", "property", "class", "parameter", "import"]
def warn_deprecation(
version: str,
deprecated_name: str,
kind: DeprecatedKind,
*,
removal_in: str | None = None,
alternative: str | None = None,
info: str | None = None,
pending: bool = False,
stacklevel: int = 2,
) -> None:
"""Warn about a call to a deprecated function.
Args:
version: SQLSpec version where the deprecation will occur
deprecated_name: Name of the deprecated function
removal_in: SQLSpec version where the deprecated function will be removed
alternative: Name of a function that should be used instead
info: Additional information
pending: Use :class:`warnings.PendingDeprecationWarning` instead of :class:`warnings.DeprecationWarning`
kind: Type of the deprecated thing
stacklevel: Warning stacklevel to report the correct caller site.
"""
parts = []
if kind == "import":
access_type = "Import of"
elif kind in {"function", "method"}:
access_type = "Call to"
else:
access_type = "Use of"
if pending:
parts.append(f"{access_type} {kind} awaiting deprecation '{deprecated_name}'") # pyright: ignore[reportUnknownMemberType]
else:
parts.append(f"{access_type} deprecated {kind} '{deprecated_name}'") # pyright: ignore[reportUnknownMemberType]
parts.extend( # pyright: ignore[reportUnknownMemberType]
(f"Deprecated in SQLSpec {version}", f"This {kind} will be removed in {removal_in or 'the next major version'}")
)
if alternative:
parts.append(f"Use {alternative!r} instead") # pyright: ignore[reportUnknownMemberType]
if info:
parts.append(info) # pyright: ignore[reportUnknownMemberType]
text = ". ".join(parts) # pyright: ignore[reportUnknownArgumentType]
warning_class = PendingDeprecationWarning if pending else DeprecationWarning
warn(text, warning_class, stacklevel=stacklevel)