You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
swarms/tests/test_docstring_parser.py

432 lines
13 KiB

"""
Test suite for the custom docstring parser implementation.
This module contains comprehensive tests to ensure the docstring parser
works correctly with various docstring formats and edge cases.
"""
import pytest
from swarms.utils.docstring_parser import (
parse,
DocstringParam,
)
class TestDocstringParser:
"""Test cases for the docstring parser functionality."""
def test_empty_docstring(self):
"""Test parsing of empty docstring."""
result = parse("")
assert result.short_description is None
assert result.params == []
def test_none_docstring(self):
"""Test parsing of None docstring."""
result = parse(None)
assert result.short_description is None
assert result.params == []
def test_whitespace_only_docstring(self):
"""Test parsing of whitespace-only docstring."""
result = parse(" \n \t \n ")
assert result.short_description is None
assert result.params == []
def test_simple_docstring_no_args(self):
"""Test parsing of simple docstring without Args section."""
docstring = """
This is a simple function.
Returns:
str: A simple string
"""
result = parse(docstring)
assert (
result.short_description == "This is a simple function."
)
assert result.params == []
def test_docstring_with_args(self):
"""Test parsing of docstring with Args section."""
docstring = """
This is a test function.
Args:
param1 (str): First parameter
param2 (int): Second parameter
param3 (bool, optional): Third parameter with default
Returns:
str: Return value description
"""
result = parse(docstring)
assert result.short_description == "This is a test function."
assert len(result.params) == 3
assert result.params[0] == DocstringParam(
"param1", "First parameter"
)
assert result.params[1] == DocstringParam(
"param2", "Second parameter"
)
assert result.params[2] == DocstringParam(
"param3", "Third parameter with default"
)
def test_docstring_with_parameters_section(self):
"""Test parsing of docstring with Parameters section."""
docstring = """
Another test function.
Parameters:
name (str): The name parameter
age (int): The age parameter
Returns:
None: Nothing is returned
"""
result = parse(docstring)
assert result.short_description == "Another test function."
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"name", "The name parameter"
)
assert result.params[1] == DocstringParam(
"age", "The age parameter"
)
def test_docstring_with_multiline_param_description(self):
"""Test parsing of docstring with multiline parameter descriptions."""
docstring = """
Function with multiline descriptions.
Args:
param1 (str): This is a very long description
that spans multiple lines and should be
properly concatenated.
param2 (int): Short description
Returns:
str: Result
"""
result = parse(docstring)
assert (
result.short_description
== "Function with multiline descriptions."
)
assert len(result.params) == 2
expected_desc = "This is a very long description that spans multiple lines and should be properly concatenated."
assert result.params[0] == DocstringParam(
"param1", expected_desc
)
assert result.params[1] == DocstringParam(
"param2", "Short description"
)
def test_docstring_without_type_annotations(self):
"""Test parsing of docstring without type annotations."""
docstring = """
Function without type annotations.
Args:
param1: First parameter without type
param2: Second parameter without type
Returns:
str: Result
"""
result = parse(docstring)
assert (
result.short_description
== "Function without type annotations."
)
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"param1", "First parameter without type"
)
assert result.params[1] == DocstringParam(
"param2", "Second parameter without type"
)
def test_pydantic_style_docstring(self):
"""Test parsing of Pydantic-style docstring."""
docstring = """
Convert a Pydantic model to a dictionary representation of functions.
Args:
pydantic_type (type[BaseModel]): The Pydantic model type to convert.
Returns:
dict[str, Any]: A dictionary representation of the functions.
"""
result = parse(docstring)
assert (
result.short_description
== "Convert a Pydantic model to a dictionary representation of functions."
)
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"pydantic_type", "The Pydantic model type to convert."
)
def test_docstring_with_various_sections(self):
"""Test parsing of docstring with multiple sections."""
docstring = """
Complex function with multiple sections.
Args:
input_data (dict): Input data dictionary
validate (bool): Whether to validate input
Returns:
dict: Processed data
Raises:
ValueError: If input is invalid
Note:
This is a note section
Example:
>>> result = complex_function({"key": "value"})
"""
result = parse(docstring)
assert (
result.short_description
== "Complex function with multiple sections."
)
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"input_data", "Input data dictionary"
)
assert result.params[1] == DocstringParam(
"validate", "Whether to validate input"
)
def test_docstring_with_see_also_section(self):
"""Test parsing of docstring with See Also section."""
docstring = """
Function with See Also section.
Args:
param1 (str): First parameter
See Also:
related_function: For related functionality
"""
result = parse(docstring)
assert (
result.short_description
== "Function with See Also section."
)
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"param1", "First parameter"
)
def test_docstring_with_see_also_underscore_section(self):
"""Test parsing of docstring with See_Also section (underscore variant)."""
docstring = """
Function with See_Also section.
Args:
param1 (str): First parameter
See_Also:
related_function: For related functionality
"""
result = parse(docstring)
assert (
result.short_description
== "Function with See_Also section."
)
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"param1", "First parameter"
)
def test_docstring_with_yields_section(self):
"""Test parsing of docstring with Yields section."""
docstring = """
Generator function.
Args:
items (list): List of items to process
Yields:
str: Processed item
"""
result = parse(docstring)
assert result.short_description == "Generator function."
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"items", "List of items to process"
)
def test_docstring_with_raises_section(self):
"""Test parsing of docstring with Raises section."""
docstring = """
Function that can raise exceptions.
Args:
value (int): Value to process
Raises:
ValueError: If value is negative
"""
result = parse(docstring)
assert (
result.short_description
== "Function that can raise exceptions."
)
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"value", "Value to process"
)
def test_docstring_with_examples_section(self):
"""Test parsing of docstring with Examples section."""
docstring = """
Function with examples.
Args:
x (int): Input value
Examples:
>>> result = example_function(5)
>>> print(result)
"""
result = parse(docstring)
assert result.short_description == "Function with examples."
assert len(result.params) == 1
assert result.params[0] == DocstringParam("x", "Input value")
def test_docstring_with_note_section(self):
"""Test parsing of docstring with Note section."""
docstring = """
Function with a note.
Args:
data (str): Input data
Note:
This function is deprecated
"""
result = parse(docstring)
assert result.short_description == "Function with a note."
assert len(result.params) == 1
assert result.params[0] == DocstringParam(
"data", "Input data"
)
def test_docstring_with_complex_type_annotations(self):
"""Test parsing of docstring with complex type annotations."""
docstring = """
Function with complex types.
Args:
data (List[Dict[str, Any]]): Complex data structure
callback (Callable[[str], int]): Callback function
optional (Optional[str], optional): Optional parameter
Returns:
Union[str, None]: Result or None
"""
result = parse(docstring)
assert (
result.short_description == "Function with complex types."
)
assert len(result.params) == 3
assert result.params[0] == DocstringParam(
"data", "Complex data structure"
)
assert result.params[1] == DocstringParam(
"callback", "Callback function"
)
assert result.params[2] == DocstringParam(
"optional", "Optional parameter"
)
def test_docstring_with_no_description(self):
"""Test parsing of docstring with no description, only Args."""
docstring = """
Args:
param1 (str): First parameter
param2 (int): Second parameter
"""
result = parse(docstring)
assert result.short_description is None
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"param1", "First parameter"
)
assert result.params[1] == DocstringParam(
"param2", "Second parameter"
)
def test_docstring_with_empty_args_section(self):
"""Test parsing of docstring with empty Args section."""
docstring = """
Function with empty Args section.
Args:
Returns:
str: Result
"""
result = parse(docstring)
assert (
result.short_description
== "Function with empty Args section."
)
assert result.params == []
def test_docstring_with_mixed_indentation(self):
"""Test parsing of docstring with mixed indentation."""
docstring = """
Function with mixed indentation.
Args:
param1 (str): First parameter
with continuation
param2 (int): Second parameter
"""
result = parse(docstring)
assert (
result.short_description
== "Function with mixed indentation."
)
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"param1", "First parameter with continuation"
)
assert result.params[1] == DocstringParam(
"param2", "Second parameter"
)
def test_docstring_with_tab_indentation(self):
"""Test parsing of docstring with tab indentation."""
docstring = """
Function with tab indentation.
Args:
param1 (str): First parameter
param2 (int): Second parameter
"""
result = parse(docstring)
assert (
result.short_description
== "Function with tab indentation."
)
assert len(result.params) == 2
assert result.params[0] == DocstringParam(
"param1", "First parameter"
)
assert result.params[1] == DocstringParam(
"param2", "Second parameter"
)
if __name__ == "__main__":
pytest.main([__file__])