Skip to content

Commit 4972815

Browse files
committed
Fixump tests
1 parent 4b5a83c commit 4972815

2 files changed

Lines changed: 37 additions & 16 deletions

File tree

providers/common/ai/src/airflow/providers/common/ai/utils/function_schema.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,34 @@
5353
)
5454

5555

56+
def _first_docstring_paragraph(obj: Any) -> str:
57+
doc = inspect.getdoc(obj)
58+
if not doc:
59+
return ""
60+
result: list[str] = []
61+
for line in doc.split("\n"):
62+
if line.strip().lower().startswith(_DOCSTRING_SECTION_PREFIXES):
63+
break
64+
result.append(line)
65+
return "\n".join(result).strip()
66+
67+
5668
def extract_function_description(fn: Callable[..., Any]) -> str:
5769
"""Return the first paragraph of *fn*'s docstring, stopping before Args/Returns sections."""
5870
# Unwrap partials to get the underlying function's docstring.
5971
if isinstance(fn, functools.partial):
6072
return extract_function_description(fn.func)
6173

62-
# Callable objects (class instances) have no __name__; use the class name.
74+
# Callable objects (class instances) have no __name__.
75+
# Prefer __call__ docstring (what calling does), then class docstring, then class name.
6376
if not hasattr(fn, "__name__"):
64-
return type(fn).__name__
77+
return (
78+
_first_docstring_paragraph(type(fn).__call__)
79+
or _first_docstring_paragraph(fn)
80+
or type(fn).__name__
81+
)
6582

66-
doc = inspect.getdoc(fn)
67-
name: str = fn.__name__ # type: ignore[assignment]
68-
if not doc:
69-
return name
70-
result: list[str] = []
71-
for line in doc.split("\n"):
72-
if line.strip().lower().startswith(_DOCSTRING_SECTION_PREFIXES):
73-
break
74-
result.append(line)
75-
return "\n".join(result).strip() or name
83+
return _first_docstring_paragraph(fn) or fn.__name__ # type: ignore[return-value]
7684

7785

7886
def build_function_json_schema(fn: Callable[..., Any]) -> dict[str, Any]:

providers/common/ai/tests/unit/common/ai/utils/test_function_schema.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,24 @@ def test_lambda_falls_back_to_lambda_name(self):
8787
f = lambda x: x
8888
assert extract_function_description(f) == "<lambda>"
8989

90-
def test_callable_object_falls_back_to_class_name(self):
90+
def test_callable_object_uses_call_docstring(self):
9191
obj = _CallableObj()
92-
# callable objects have no __name__; falls back to type name
93-
result = extract_function_description(obj)
94-
assert result == "_CallableObj"
92+
# prefers __call__ docstring over class docstring over class name
93+
assert extract_function_description(obj) == "Process value."
94+
95+
def test_callable_object_falls_back_to_class_docstring(self):
96+
class _NoCallDoc:
97+
"""Describes the class."""
98+
99+
def __call__(self, x: int) -> int: ...
100+
101+
assert extract_function_description(_NoCallDoc()) == "Describes the class."
102+
103+
def test_callable_object_falls_back_to_class_name(self):
104+
class _NoDocs:
105+
def __call__(self, x: int) -> int: ...
106+
107+
assert extract_function_description(_NoDocs()) == "_NoDocs"
95108

96109
@pytest.mark.parametrize(
97110
"header",

0 commit comments

Comments
 (0)