docs: Fix bug that caused the word "Deprecated" to appear twice in doc-strings (#17615)

The current issue:
Most of the deprecation descriptions are duplicated. For example:
`[Deprecated] Chat Agent.[Deprecated] Chat Agent.` for the [ChatAgent
class](https://api.python.langchain.com/en/latest/langchain_api_reference.html#classes)
description.

NOTE: I've tested it only with new ut! I cannot build API Reference
locally :(
pull/17618/head
Leonid Ganeline 3 months ago committed by GitHub
parent 88af4fd514
commit 0835ebad70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -245,10 +245,9 @@ def deprecated(
old_doc = inspect.cleandoc(old_doc or "").strip("\n")
# old_doc can be None
if not old_doc:
new_doc = "[*Deprecated*]"
else:
new_doc = f"[*Deprecated*] {old_doc}"
old_doc = ""
# Modify the docstring to include a deprecation notice.
notes_header = "\nNotes\n-----"
@ -258,7 +257,7 @@ def deprecated(
addendum,
]
details = " ".join([component.strip() for component in components if component])
new_doc += (
new_doc = (
f"[*Deprecated*] {old_doc}\n"
f"{notes_header if notes_header not in old_doc else ''}\n"
f".. deprecated:: {since}\n"

@ -129,7 +129,7 @@ def test_deprecated_function() -> None:
doc = deprecated_function.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
assert not inspect.iscoroutinefunction(deprecated_function)
@ -151,7 +151,7 @@ async def test_deprecated_async_function() -> None:
doc = deprecated_function.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
assert inspect.iscoroutinefunction(deprecated_async_function)
@ -171,7 +171,7 @@ def test_deprecated_method() -> None:
doc = obj.deprecated_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
assert not inspect.iscoroutinefunction(obj.deprecated_method)
@ -194,7 +194,7 @@ async def test_deprecated_async_method() -> None:
doc = obj.deprecated_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
assert inspect.iscoroutinefunction(obj.deprecated_async_method)
@ -213,7 +213,7 @@ def test_deprecated_classmethod() -> None:
doc = ClassWithDeprecatedMethods.deprecated_classmethod.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
def test_deprecated_staticmethod() -> None:
@ -233,7 +233,7 @@ def test_deprecated_staticmethod() -> None:
)
doc = ClassWithDeprecatedMethods.deprecated_staticmethod.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
def test_deprecated_property() -> None:
@ -253,7 +253,7 @@ def test_deprecated_property() -> None:
)
doc = ClassWithDeprecatedMethods.deprecated_property.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")
def test_whole_class_deprecation() -> None:
@ -289,6 +289,88 @@ def test_whole_class_deprecation() -> None:
"The function `deprecated_method` was deprecated in "
"LangChain 2.0.0 and will be removed in 3.0.0"
)
# [*Deprecated*] should be inserted only once:
if obj.__doc__ is not None:
assert obj.__doc__.count("[*Deprecated*]") == 1
def test_whole_class_inherited_deprecation() -> None:
"""Test whole class deprecation for inherited class.
The original version of deprecation decorator created duplicates with
'[*Deprecated*]'.
"""
# Test whole class deprecation
@deprecated(since="2.0.0", removal="3.0.0")
class DeprecatedClass:
def __init__(self) -> None:
"""original doc"""
pass
@deprecated(since="2.0.0", removal="3.0.0")
def deprecated_method(self) -> str:
"""original doc"""
return "This is a deprecated method."
@deprecated(since="2.2.0", removal="3.2.0")
class InheritedDeprecatedClass(DeprecatedClass):
"""Inherited deprecated class."""
def __init__(self) -> None:
"""original doc"""
pass
@deprecated(since="2.2.0", removal="3.2.0")
def deprecated_method(self) -> str:
"""original doc"""
return "This is a deprecated method."
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
obj = DeprecatedClass()
assert obj.deprecated_method() == "This is a deprecated method."
assert len(warning_list) == 2
warning = warning_list[0].message
assert str(warning) == (
"The class `tests.unit_tests._api.test_deprecation.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"
)
# if [*Deprecated*] was inserted only once:
if obj.__doc__ is not None:
assert obj.__doc__.count("[*Deprecated*]") == 1
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
obj = InheritedDeprecatedClass()
assert obj.deprecated_method() == "This is a deprecated method."
assert len(warning_list) == 2
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"
)
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"
)
# if [*Deprecated*] was inserted only once:
if obj.__doc__ is not None:
assert obj.__doc__.count("[*Deprecated*]") == 1
assert "[*Deprecated*] Inherited deprecated class." in obj.__doc__
# Tests with pydantic models
@ -314,4 +396,4 @@ def test_deprecated_method_pydantic() -> None:
doc = obj.deprecated_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Deprecated*] original doc")
assert doc.startswith("[*Deprecated*] original doc")

Loading…
Cancel
Save