Skip to content

Commit

Permalink
docs: Fix bug that caused the word "Beta" to appear twice in doc-stri…
Browse files Browse the repository at this point in the history
…ngs (langchain-ai#17704)

The current issue:
Several beta descriptions in the API Reference are duplicated. For
example:
`[Beta] Get a context value.[Beta] Get a context value.` for the
[ContextGet
class](https://api.python.langchain.com/en/latest/core_api_reference.html#module-langchain_core.beta)
description.

NOTE: I've tested it only with a new ut! I cannot build API Reference
locally :(
This PR related to langchain-ai#17615
  • Loading branch information
leo-gan authored Feb 19, 2024
1 parent 73edf17 commit 1d2aa19
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 15 deletions.
7 changes: 3 additions & 4 deletions libs/core/langchain_core/_api/beta_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,9 @@ def finalize( # type: ignore

old_doc = inspect.cleandoc(old_doc or "").strip("\n")

# old_doc can be None
if not old_doc:
new_doc = "[*Beta*]"
else:
new_doc = f"[*Beta*] {old_doc}"
old_doc = ""

# Modify the docstring to include a beta notice.
notes_header = "\nNotes\n-----"
Expand All @@ -218,7 +217,7 @@ def finalize( # type: ignore
addendum,
]
details = " ".join([component.strip() for component in components if component])
new_doc += (
new_doc = (
f"[*Beta*] {old_doc}\n"
f"{notes_header if notes_header not in old_doc else ''}\n"
f".. beta::\n"
Expand Down
88 changes: 77 additions & 11 deletions libs/core/tests/unit_tests/_api/test_beta_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def test_beta_function() -> None:

doc = beta_function.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")

assert not inspect.iscoroutinefunction(beta_function)

Expand All @@ -132,7 +132,7 @@ async def test_beta_async_function() -> None:

doc = beta_function.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")

assert inspect.iscoroutinefunction(beta_async_function)

Expand All @@ -152,7 +152,7 @@ def test_beta_method() -> None:

doc = obj.beta_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")

assert not inspect.iscoroutinefunction(obj.beta_method)

Expand All @@ -173,7 +173,7 @@ async def test_beta_async_method() -> None:

doc = obj.beta_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")

assert inspect.iscoroutinefunction(obj.beta_async_method)

Expand All @@ -192,7 +192,7 @@ def test_beta_classmethod() -> None:

doc = ClassWithBetaMethods.beta_classmethod.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")


def test_beta_staticmethod() -> None:
Expand All @@ -211,7 +211,7 @@ def test_beta_staticmethod() -> None:
)
doc = ClassWithBetaMethods.beta_staticmethod.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")


def test_beta_property() -> None:
Expand All @@ -231,13 +231,12 @@ def test_beta_property() -> None:
)
doc = ClassWithBetaMethods.beta_property.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")


def test_whole_class_deprecation() -> None:
"""Test whole class deprecation."""
def test_whole_class_beta() -> None:
"""Test whole class beta status."""

# Test whole class deprecation
@beta()
class BetaClass:
def __init__(self) -> None:
Expand Down Expand Up @@ -269,6 +268,73 @@ def beta_method(self) -> str:
)


def test_whole_class_inherited_beta() -> None:
"""Test whole class beta status for inherited class.
The original version of beta decorator created duplicates with
'[*Beta*]'.
"""

# Test whole class beta status
@beta()
class BetaClass:
@beta()
def beta_method(self) -> str:
"""original doc"""
return "This is a beta method."

@beta()
class InheritedBetaClass(BetaClass):
@beta()
def beta_method(self) -> str:
"""original doc"""
return "This is a beta method 2."

with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")

obj = BetaClass()
assert obj.beta_method() == "This is a beta method."

assert len(warning_list) == 2
warning = warning_list[0].message
assert str(warning) == (
"The class `BetaClass` is in beta. It is actively being worked on, so the "
"API may change."
)

warning = warning_list[1].message
assert str(warning) == (
"The function `beta_method` is in beta. It is actively being worked on, so "
"the API may change."
)

with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")

obj = InheritedBetaClass()
assert obj.beta_method() == "This is a beta method 2."

assert len(warning_list) == 2
warning = warning_list[0].message
assert str(warning) == (
"The class `InheritedBetaClass` is in beta. "
"It is actively being worked on, so the "
"API may change."
)

warning = warning_list[1].message
assert str(warning) == (
"The function `beta_method` is in beta. "
"It is actively being worked on, so "
"the API may change."
)

# if [*Beta*] was inserted only once:
if obj.__doc__ is not None:
assert obj.__doc__.count("[*Beta*]") == 1


# Tests with pydantic models
class MyModel(BaseModel):
@beta()
Expand All @@ -292,4 +358,4 @@ def test_beta_method_pydantic() -> None:

doc = obj.beta_method.__doc__
assert isinstance(doc, str)
assert doc.startswith("[*Beta*] original doc")
assert doc.startswith("[*Beta*] original doc")

0 comments on commit 1d2aa19

Please sign in to comment.