diff --git a/libs/community/langchain_community/chat_models/huggingface.py b/libs/community/langchain_community/chat_models/huggingface.py index f03c0c75228..68aaabaddd5 100644 --- a/libs/community/langchain_community/chat_models/huggingface.py +++ b/libs/community/langchain_community/chat_models/huggingface.py @@ -39,7 +39,7 @@ DEFAULT_SYSTEM_PROMPT = """You are a helpful, respectful, and honest assistant." @deprecated( since="0.0.37", removal="0.3", - alternative_import=("from langchain_huggingface import ChatHuggingFace"), + alternative_import="langchain_huggingface.ChatHuggingFace", ) class ChatHuggingFace(BaseChatModel): """ diff --git a/libs/core/langchain_core/_api/deprecation.py b/libs/core/langchain_core/_api/deprecation.py index 1c253d99215..b5105db7f8b 100644 --- a/libs/core/langchain_core/_api/deprecation.py +++ b/libs/core/langchain_core/_api/deprecation.py @@ -33,6 +33,25 @@ class LangChainPendingDeprecationWarning(PendingDeprecationWarning): T = TypeVar("T", bound=Union[Type, Callable[..., Any]]) +def _validate_deprecation_params( + pending: bool, + removal: str, + alternative: str, + alternative_import: str, +) -> None: + """Validate the deprecation parameters.""" + if pending and removal: + raise ValueError("A pending deprecation cannot have a scheduled removal") + if alternative and alternative_import: + raise ValueError("Cannot specify both alternative and alternative_import") + + if alternative_import and "." not in alternative_import: + raise ValueError( + "alternative_import must be a fully qualified module path. Got " + f" {alternative_import}" + ) + + def deprecated( since: str, *, @@ -99,6 +118,7 @@ def deprecated( def the_function_to_deprecate(): pass """ + _validate_deprecation_params(pending, removal, alternative, alternative_import) def deprecate( obj: T, @@ -337,13 +357,6 @@ def warn_deprecated( since. Set to other Falsy values to not schedule a removal date. Cannot be used together with pending. """ - if pending and removal: - raise ValueError("A pending deprecation cannot have a scheduled removal") - if alternative and alternative_import: - raise ValueError("Cannot specify both alternative and alternative_import") - if alternative_import and "." not in alternative_import: - raise ValueError("alternative_import must be a fully qualified module path") - if not pending: if not removal: removal = f"in {removal}" if removal else "within ?? minor releases" diff --git a/libs/core/tests/unit_tests/_api/test_deprecation.py b/libs/core/tests/unit_tests/_api/test_deprecation.py index fc05c002575..a34cbcffbc8 100644 --- a/libs/core/tests/unit_tests/_api/test_deprecation.py +++ b/libs/core/tests/unit_tests/_api/test_deprecation.py @@ -401,3 +401,14 @@ def test_deprecated_method_pydantic() -> None: doc = obj.deprecated_method.__doc__ assert isinstance(doc, str) assert doc.startswith("[*Deprecated*] original doc") + + +def test_raise_error_for_bad_decorator() -> None: + """Verify that errors raised on init rather than on use.""" + # Should not specify both `alternative` and `alternative_import` + with pytest.raises(ValueError): + + @deprecated(since="2.0.0", alternative="NewClass", alternative_import="hello") + def deprecated_function() -> str: + """original doc""" + return "This is a deprecated function."