libs/core/langchain_core/_api/beta_decorator.py PYTHON 267 lines View on github.com → Search inside
1"""Helper functions for marking parts of the LangChain API as beta.23This module was loosely adapted from matplotlib's [`_api/deprecation.py`](https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/_api/deprecation.py)4module.56!!! warning78    This module is for internal use only. Do not use it in your own code. We may change9    the API at any time with no warning.10"""1112import contextlib13import functools14import inspect15import warnings16from collections.abc import Callable, Generator17from typing import Any, TypeVar, cast1819from langchain_core._api.internal import is_caller_internal202122class LangChainBetaWarning(DeprecationWarning):23    """A class for issuing beta warnings for LangChain users."""242526# PUBLIC API272829T = TypeVar("T", bound=Callable[..., Any] | type | property)303132def beta(33    *,34    message: str = "",35    name: str = "",36    obj_type: str = "",37    addendum: str = "",38) -> Callable[[T], T]:39    """Decorator to mark a function, a class, or a property as beta.4041    When marking a classmethod, a staticmethod, or a property, the `@beta` decorator42    should go *under* `@classmethod` and `@staticmethod` (i.e., `beta` should directly43    decorate the underlying callable), but *over* `@property`.4445    When marking a class `C` intended to be used as a base class in a multiple46    inheritance hierarchy, `C` *must* define an `__init__` method (if `C` instead47    inherited its `__init__` from its own base class, then `@beta` would mess up48    `__init__` inheritance when installing its own (annotation-emitting) `C.__init__`).4950    Args:51        message: Override the default beta message.5253            The %(since)s, %(name)s, %(alternative)s, %(obj_type)s, %(addendum)s, and54            %(removal)s format specifiers will be replaced by the values of the55            respective arguments passed to this function.56        name: The name of the beta object.57        obj_type: The object type being beta.58        addendum: Additional text appended directly to the final message.5960    Returns:61        A decorator which can be used to mark functions or classes as beta.6263    Example:64        ```python65        @beta66        def the_function_to_annotate():67            pass68        ```69    """7071    def beta(72        obj: T,73        *,74        _obj_type: str = obj_type,75        _name: str = name,76        _message: str = message,77        _addendum: str = addendum,78    ) -> T:79        """Implementation of the decorator returned by `beta`."""8081        def emit_warning() -> None:82            """Emit the warning."""83            warn_beta(84                message=_message,85                name=_name,86                obj_type=_obj_type,87                addendum=_addendum,88            )8990        warned = False9192        def warning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:93            """Wrapper for the original wrapped callable that emits a warning.9495            Args:96                *args: The positional arguments to the function.97                **kwargs: The keyword arguments to the function.9899            Returns:100                The return value of the function being wrapped.101            """102            nonlocal warned103            if not warned and not is_caller_internal():104                warned = True105                emit_warning()106            return wrapped(*args, **kwargs)107108        async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:109            """Same as warning_emitting_wrapper, but for async functions."""110            nonlocal warned111            if not warned and not is_caller_internal():112                warned = True113                emit_warning()114            return await wrapped(*args, **kwargs)115116        if isinstance(obj, type):117            if not _obj_type:118                _obj_type = "class"119            wrapped = obj.__init__  # type: ignore[misc]120            _name = _name or obj.__qualname__121            old_doc = obj.__doc__122123            def finalize(_: Callable[..., Any], new_doc: str, /) -> T:124                """Finalize the annotation of a class."""125                # Can't set new_doc on some extension objects.126                with contextlib.suppress(AttributeError):127                    obj.__doc__ = new_doc128129                def warn_if_direct_instance(130                    self: Any, *args: Any, **kwargs: Any131                ) -> Any:132                    """Warn that the class is in beta."""133                    nonlocal warned134                    if not warned and type(self) is obj and not is_caller_internal():135                        warned = True136                        emit_warning()137                    return wrapped(self, *args, **kwargs)138139                obj.__init__ = functools.wraps(obj.__init__)(  # type: ignore[misc]140                    warn_if_direct_instance141                )142                return obj143144        elif isinstance(obj, property):145            if not _obj_type:146                _obj_type = "attribute"147            wrapped = None148            _name = _name or (obj.fget and obj.fget.__qualname__) or "<property>"149            old_doc = obj.__doc__150151            # `obj.fget`/`fset`/`fdel` are typed `Callable | None`, so the `and`152            # short-circuits guard the calls for the type checker. Each wrapper is153            # only installed when its accessor is truthy (see `finalize` below), so154            # the guards never short-circuit at runtime  do not "simplify" them155            # away or mypy's `warn_unreachable` will flag the accessor as `None`.156            def _fget(instance: Any) -> Any:157                if instance is not None:158                    emit_warning()159                return obj.fget and obj.fget(instance)160161            def _fset(instance: Any, value: Any) -> None:162                if instance is not None:163                    emit_warning()164                obj.fset and obj.fset(instance, value)165166            def _fdel(instance: Any) -> None:167                if instance is not None:168                    emit_warning()169                obj.fdel and obj.fdel(instance)170171            def finalize(_: Callable[..., Any], new_doc: str, /) -> T:172                """Finalize the property."""173                return cast(174                    "T",175                    property(176                        fget=_fget if obj.fget else None,177                        fset=_fset if obj.fset else None,178                        fdel=_fdel if obj.fdel else None,179                        doc=new_doc,180                    ),181                )182183        else:184            _name = _name or obj.__qualname__185            if not _obj_type:186                # edge case: when a function is within another function187                # within a test, this will call it a "method" not a "function"188                _obj_type = "function" if "." not in _name else "method"189            wrapped = obj190            old_doc = wrapped.__doc__191192            def finalize(wrapper: Callable[..., Any], new_doc: str, /) -> T:193                """Wrap the wrapped function using the wrapper and update the docstring.194195                Args:196                    wrapper: The wrapper function.197                    new_doc: The new docstring.198199                Returns:200                    The wrapped function.201                """202                wrapper = functools.wraps(wrapped)(wrapper)203                wrapper.__doc__ = new_doc204                return cast("T", wrapper)205206        old_doc = inspect.cleandoc(old_doc or "").strip("\n") or ""207        components = [message, addendum]208        details = " ".join([component.strip() for component in components if component])209        new_doc = f".. beta::\n   {details}\n\n{old_doc}\n"210211        if inspect.iscoroutinefunction(obj):212            return finalize(awarning_emitting_wrapper, new_doc)213        return finalize(warning_emitting_wrapper, new_doc)214215    return beta216217218@contextlib.contextmanager219def suppress_langchain_beta_warning() -> Generator[None, None, None]:220    """Context manager to suppress `LangChainDeprecationWarning`."""221    with warnings.catch_warnings():222        warnings.simplefilter("ignore", LangChainBetaWarning)223        yield224225226def warn_beta(227    *,228    message: str = "",229    name: str = "",230    obj_type: str = "",231    addendum: str = "",232) -> None:233    """Display a standardized beta annotation.234235    Args:236        message: Override the default beta message.237238            The %(name)s, %(obj_type)s, %(addendum)s format specifiers will be replaced239            by the values of the respective arguments passed to this function.240        name: The name of the annotated object.241        obj_type: The object type being annotated.242        addendum: Additional text appended directly to the final message.243    """244    if not message:245        message = ""246247        if obj_type:248            message += f"The {obj_type} `{name}`"249        else:250            message += f"`{name}`"251252        message += " is in beta. It is actively being worked on, so the API may change."253254        if addendum:255            message += f" {addendum}"256257    warning = LangChainBetaWarning(message)258    warnings.warn(warning, category=LangChainBetaWarning, stacklevel=4)259260261def surface_langchain_beta_warnings() -> None:262    """Unmute LangChain beta warnings."""263    warnings.filterwarnings(264        "default",265        category=LangChainBetaWarning,266    )

Code quality findings 8

Ensure functions have docstrings for documentation
missing-docstring
def beta(
Ensure functions have docstrings for documentation
missing-docstring
def the_function_to_annotate():
Ensure functions have docstrings for documentation
missing-docstring
def beta(
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(obj, type):
Ensure functions have docstrings for documentation
missing-docstring
def warn_if_direct_instance(
Use isinstance() for type checking instead of type()
type-check
if not warned and type(self) is obj and not is_caller_internal():
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
elif isinstance(obj, property):
Ensure functions have docstrings for documentation
missing-docstring
def warn_beta(

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.