Skip to content

Commit

Permalink
core: deprecation default to qualname (langchain-ai#20578)
Browse files Browse the repository at this point in the history
  • Loading branch information
efriis authored Apr 18, 2024
1 parent 7d0a008 commit 3425988
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 32 deletions.
32 changes: 22 additions & 10 deletions libs/core/langchain_core/_api/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def deprecated(
obj_type: str = "",
addendum: str = "",
removal: str = "",
package: str = "",
) -> Callable[[T], T]:
"""Decorator to mark a function, a class, or a property as deprecated.
Expand Down Expand Up @@ -109,6 +110,7 @@ def deprecate(
_alternative_import: str = alternative_import,
_pending: bool = pending,
_addendum: str = addendum,
_package: str = package,
) -> T:
"""Implementation of the decorator returned by `deprecated`."""

Expand All @@ -124,6 +126,7 @@ def emit_warning() -> None:
obj_type=_obj_type,
addendum=_addendum,
removal=removal,
package=_package,
)

warned = False
Expand Down Expand Up @@ -153,13 +156,13 @@ async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:
emit_warning()
return await wrapped(*args, **kwargs)

_package = _package or obj.__module__.split(".")[0].replace("_", "-")

if isinstance(obj, type):
if not _obj_type:
_obj_type = "class"
wrapped = obj.__init__ # type: ignore
_name = _name or (
f"{obj.__module__}.{obj.__name__}" if obj.__module__ else obj.__name__
)
_name = _name or obj.__qualname__
old_doc = obj.__doc__

def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
Expand Down Expand Up @@ -188,7 +191,7 @@ def warn_if_direct_instance(
if not _obj_type:
_obj_type = "attribute"
wrapped = None
_name = _name or obj.fget.__name__
_name = _name or obj.fget.__qualname__
old_doc = obj.__doc__

class _deprecated_property(property):
Expand Down Expand Up @@ -227,10 +230,12 @@ def finalize(wrapper: Callable[..., Any], new_doc: str) -> Any:
)

else:
_name = _name or obj.__qualname__
if not _obj_type:
_obj_type = "function"
# edge case: when a function is within another function
# within a test, this will call it a "method" not a "function"
_obj_type = "function" if "." not in _name else "method"
wrapped = obj
_name = _name or obj.__name__
old_doc = wrapped.__doc__

def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
Expand Down Expand Up @@ -261,7 +266,9 @@ def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
addendum,
]
details = " ".join([component.strip() for component in components if component])
package = _name.split(".")[0].replace("_", "-") if "." in _name else None
package = (
_package or _name.split(".")[0].replace("_", "-") if "." in _name else None
)
since_str = f"{package}=={since}" if package else since
new_doc = (
f"[*Deprecated*] {old_doc}\n"
Expand Down Expand Up @@ -299,6 +306,7 @@ def warn_deprecated(
obj_type: str = "",
addendum: str = "",
removal: str = "",
package: str = "",
) -> None:
"""Display a standardized deprecation.
Expand Down Expand Up @@ -348,7 +356,11 @@ def warn_deprecated(

if not message:
message = ""
package = name.split(".")[0].replace("_", "-") if "." in name else "LangChain"
_package = (
package or name.split(".")[0].replace("_", "-")
if "." in name
else "LangChain"
)

if obj_type:
message += f"The {obj_type} `{name}`"
Expand All @@ -358,14 +370,14 @@ def warn_deprecated(
if pending:
message += " will be deprecated in a future version"
else:
message += f" was deprecated in {package} {since}"
message += f" was deprecated in {_package} {since}"

if removal:
message += f" and will be removed {removal}"

if alternative_import:
alt_package = alternative_import.split(".")[0].replace("_", "-")
if alt_package == package:
if alt_package == _package:
message += f". Use {alternative_import} instead."
else:
alt_module, alt_name = alternative_import.rsplit(".", 1)
Expand Down
48 changes: 26 additions & 22 deletions libs/core/tests/unit_tests/_api/test_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ def test_deprecated_method() -> None:
assert len(warning_list) == 1
warning = warning_list[0].message
assert str(warning) == (
"The function `deprecated_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `ClassWithDeprecatedMethods.deprecated_method` was deprecated"
" in tests 2.0.0 and will be removed in 3.0.0"
)

doc = obj.deprecated_method.__doc__
Expand All @@ -188,8 +188,8 @@ async def test_deprecated_async_method() -> None:
assert len(warning_list) == 1
warning = warning_list[0].message
assert str(warning) == (
"The function `deprecated_async_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `ClassWithDeprecatedMethods.deprecated_async_method` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)

doc = obj.deprecated_method.__doc__
Expand All @@ -207,8 +207,8 @@ def test_deprecated_classmethod() -> None:
assert len(warning_list) == 1
warning = warning_list[0].message
assert str(warning) == (
"The function `deprecated_classmethod` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `ClassWithDeprecatedMethods.deprecated_classmethod` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)

doc = ClassWithDeprecatedMethods.deprecated_classmethod.__doc__
Expand All @@ -228,8 +228,8 @@ def test_deprecated_staticmethod() -> None:
warning = warning_list[0].message

assert str(warning) == (
"The function `deprecated_staticmethod` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `ClassWithDeprecatedMethods.deprecated_staticmethod` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)
doc = ClassWithDeprecatedMethods.deprecated_staticmethod.__doc__
assert isinstance(doc, str)
Expand All @@ -248,8 +248,8 @@ def test_deprecated_property() -> None:
warning = warning_list[0].message

assert str(warning) == (
"The function `deprecated_property` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `ClassWithDeprecatedMethods.deprecated_property` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)
doc = ClassWithDeprecatedMethods.deprecated_property.__doc__
assert isinstance(doc, str)
Expand Down Expand Up @@ -280,14 +280,15 @@ def deprecated_method(self) -> str:
assert len(warning_list) == 2
warning = warning_list[0].message
assert str(warning) == (
"The class `tests.unit_tests._api.test_deprecation.DeprecatedClass` was "
"The class `test_whole_class_deprecation.<locals>.DeprecatedClass` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)

warning = warning_list[1].message
assert str(warning) == (
"The function `deprecated_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `test_whole_class_deprecation.<locals>.DeprecatedClass."
"deprecated_method` was deprecated in "
"tests 2.0.0 and will be removed in 3.0.0"
)
# [*Deprecated*] should be inserted only once:
if obj.__doc__ is not None:
Expand Down Expand Up @@ -335,14 +336,16 @@ def deprecated_method(self) -> str:
assert len(warning_list) == 2
warning = warning_list[0].message
assert str(warning) == (
"The class `tests.unit_tests._api.test_deprecation.DeprecatedClass` was "
"The class `test_whole_class_inherited_deprecation.<locals>."
"DeprecatedClass` was "
"deprecated in tests 2.0.0 and will be removed in 3.0.0"
)

warning = warning_list[1].message
assert str(warning) == (
"The function `deprecated_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `test_whole_class_inherited_deprecation.<locals>."
"DeprecatedClass.deprecated_method` was deprecated in "
"tests 2.0.0 and will be removed in 3.0.0"
)
# if [*Deprecated*] was inserted only once:
if obj.__doc__ is not None:
Expand All @@ -358,14 +361,15 @@ def deprecated_method(self) -> str:
warning = warning_list[0].message
assert str(warning) == (
"The class "
"`tests.unit_tests._api.test_deprecation.InheritedDeprecatedClass` "
"was deprecated in tests 2.2.0 and will be removed in 3.2.0"
"`test_whole_class_inherited_deprecation.<locals>.InheritedDeprecatedClass`"
" was deprecated in tests 2.2.0 and will be removed in 3.2.0"
)

warning = warning_list[1].message
assert str(warning) == (
"The function `deprecated_method` was deprecated in "
"LangChain 2.2.0 and will be removed in 3.2.0"
"The method `test_whole_class_inherited_deprecation.<locals>."
"InheritedDeprecatedClass.deprecated_method` was deprecated in "
"tests 2.2.0 and will be removed in 3.2.0"
)
# if [*Deprecated*] was inserted only once:
if obj.__doc__ is not None:
Expand All @@ -390,8 +394,8 @@ def test_deprecated_method_pydantic() -> None:
assert len(warning_list) == 1
warning = warning_list[0].message
assert str(warning) == (
"The function `deprecated_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
"The method `MyModel.deprecated_method` was deprecated in "
"tests 2.0.0 and will be removed in 3.0.0"
)

doc = obj.deprecated_method.__doc__
Expand Down

0 comments on commit 3425988

Please sign in to comment.