| """Tests for Google-style docstring routines.""" |
|
|
| import typing as T |
|
|
| import pytest |
| from docstring_parser.common import ParseError, RenderingStyle |
| from docstring_parser.google import ( |
| GoogleParser, |
| Section, |
| SectionType, |
| compose, |
| parse, |
| ) |
|
|
|
|
| def test_google_parser_unknown_section() -> None: |
| """Test parsing an unknown section with default GoogleParser |
| configuration. |
| """ |
| parser = GoogleParser() |
| docstring = parser.parse( |
| """ |
| Unknown: |
| spam: a |
| """ |
| ) |
| assert docstring.short_description == "Unknown:" |
| assert docstring.long_description == "spam: a" |
| assert len(docstring.meta) == 0 |
|
|
|
|
| def test_google_parser_multi_line_parameter_type() -> None: |
| """Test parsing a multi-line parameter type with default GoogleParser""" |
| parser = GoogleParser() |
| docstring = parser.parse( |
| """Description of the function. |
| |
| Args: |
| output_type (Literal["searchResults", "sourcedAnswer", |
| "structured"]): The type of output. |
| This can be one of the following: |
| - "searchResults": Represents the search results. |
| - "sourcedAnswer": Represents a sourced answer. |
| - "structured": Represents a structured output format. |
| |
| Returns: |
| bool: Indicates success or failure. |
| |
| """ |
| ) |
| assert docstring.params[0].arg_name == "output_type" |
|
|
|
|
| def test_google_parser_custom_sections() -> None: |
| """Test parsing an unknown section with custom GoogleParser |
| configuration. |
| """ |
| parser = GoogleParser( |
| [ |
| Section("DESCRIPTION", "desc", SectionType.SINGULAR), |
| Section("ARGUMENTS", "param", SectionType.MULTIPLE), |
| Section("ATTRIBUTES", "attribute", SectionType.MULTIPLE), |
| Section("EXAMPLES", "examples", SectionType.SINGULAR), |
| ], |
| title_colon=False, |
| ) |
| docstring = parser.parse( |
| """ |
| DESCRIPTION |
| This is the description. |
| |
| ARGUMENTS |
| arg1: first arg |
| arg2: second arg |
| |
| ATTRIBUTES |
| attr1: first attribute |
| attr2: second attribute |
| |
| EXAMPLES |
| Many examples |
| More examples |
| """ |
| ) |
|
|
| assert docstring.short_description is None |
| assert docstring.long_description is None |
| assert len(docstring.meta) == 6 |
| assert docstring.meta[0].args == ["desc"] |
| assert docstring.meta[0].description == "This is the description." |
| assert docstring.meta[1].args == ["param", "arg1"] |
| assert docstring.meta[1].description == "first arg" |
| assert docstring.meta[2].args == ["param", "arg2"] |
| assert docstring.meta[2].description == "second arg" |
| assert docstring.meta[3].args == ["attribute", "attr1"] |
| assert docstring.meta[3].description == "first attribute" |
| assert docstring.meta[4].args == ["attribute", "attr2"] |
| assert docstring.meta[4].description == "second attribute" |
| assert docstring.meta[5].args == ["examples"] |
| assert docstring.meta[5].description == "Many examples\nMore examples" |
|
|
|
|
| def test_google_parser_custom_sections_after() -> None: |
| """Test parsing an unknown section with custom GoogleParser configuration |
| that was set at a runtime. |
| """ |
| parser = GoogleParser(title_colon=False) |
| parser.add_section(Section("Note", "note", SectionType.SINGULAR)) |
| docstring = parser.parse( |
| """ |
| short description |
| |
| Note: |
| a note |
| """ |
| ) |
| assert docstring.short_description == "short description" |
| assert docstring.long_description == "Note:\n a note" |
|
|
| docstring = parser.parse( |
| """ |
| short description |
| |
| Note a note |
| """ |
| ) |
| assert docstring.short_description == "short description" |
| assert docstring.long_description == "Note a note" |
|
|
| docstring = parser.parse( |
| """ |
| short description |
| |
| Note |
| a note |
| """ |
| ) |
| assert len(docstring.meta) == 1 |
| assert docstring.meta[0].args == ["note"] |
| assert docstring.meta[0].description == "a note" |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected", |
| [ |
| ("", None), |
| ("\n", None), |
| ("Short description", "Short description"), |
| ("\nShort description\n", "Short description"), |
| ("\n Short description\n", "Short description"), |
| ], |
| ) |
| def test_short_description(source: str, expected: str) -> None: |
| """Test parsing short description.""" |
| docstring = parse(source) |
| assert docstring.short_description == expected |
| assert docstring.long_description is None |
| assert not docstring.meta |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected_short_desc, expected_long_desc, expected_blank", |
| [ |
| ( |
| "Short description\n\nLong description", |
| "Short description", |
| "Long description", |
| True, |
| ), |
| ( |
| """ |
| Short description |
| |
| Long description |
| """, |
| "Short description", |
| "Long description", |
| True, |
| ), |
| ( |
| """ |
| Short description |
| |
| Long description |
| Second line |
| """, |
| "Short description", |
| "Long description\nSecond line", |
| True, |
| ), |
| ( |
| "Short description\nLong description", |
| "Short description", |
| "Long description", |
| False, |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| """, |
| "Short description", |
| "Long description", |
| False, |
| ), |
| ( |
| "\nShort description\nLong description\n", |
| "Short description", |
| "Long description", |
| False, |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| Second line |
| """, |
| "Short description", |
| "Long description\nSecond line", |
| False, |
| ), |
| ], |
| ) |
| def test_long_description( |
| source: str, |
| expected_short_desc: str, |
| expected_long_desc: str, |
| expected_blank: bool, |
| ) -> None: |
| """Test parsing long description.""" |
| docstring = parse(source) |
| assert docstring.short_description == expected_short_desc |
| assert docstring.long_description == expected_long_desc |
| assert docstring.blank_after_short_description == expected_blank |
| assert not docstring.meta |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected_short_desc, expected_long_desc, " |
| "expected_blank_short_desc, expected_blank_long_desc", |
| [ |
| ( |
| """ |
| Short description |
| Args: |
| asd: |
| """, |
| "Short description", |
| None, |
| False, |
| False, |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| Args: |
| asd: |
| """, |
| "Short description", |
| "Long description", |
| False, |
| False, |
| ), |
| ( |
| """ |
| Short description |
| First line |
| Second line |
| Args: |
| asd: |
| """, |
| "Short description", |
| "First line\n Second line", |
| False, |
| False, |
| ), |
| ( |
| """ |
| Short description |
| |
| First line |
| Second line |
| Args: |
| asd: |
| """, |
| "Short description", |
| "First line\n Second line", |
| True, |
| False, |
| ), |
| ( |
| """ |
| Short description |
| |
| First line |
| Second line |
| |
| Args: |
| asd: |
| """, |
| "Short description", |
| "First line\n Second line", |
| True, |
| True, |
| ), |
| ( |
| """ |
| Args: |
| asd: |
| """, |
| None, |
| None, |
| False, |
| False, |
| ), |
| ], |
| ) |
| def test_meta_newlines( |
| source: str, |
| expected_short_desc: T.Optional[str], |
| expected_long_desc: T.Optional[str], |
| expected_blank_short_desc: bool, |
| expected_blank_long_desc: bool, |
| ) -> None: |
| """Test parsing newlines around description sections.""" |
| docstring = parse(source) |
| assert docstring.short_description == expected_short_desc |
| assert docstring.long_description == expected_long_desc |
| assert docstring.blank_after_short_description == expected_blank_short_desc |
| assert docstring.blank_after_long_description == expected_blank_long_desc |
| assert len(docstring.meta) == 1 |
|
|
|
|
| def test_meta_with_multiline_description() -> None: |
| """Test parsing multiline meta documentation.""" |
| docstring = parse( |
| """ |
| Short description |
| |
| Args: |
| spam: asd |
| 1 |
| 2 |
| 3 |
| """ |
| ) |
| assert docstring.short_description == "Short description" |
| assert len(docstring.meta) == 1 |
| assert docstring.meta[0].args == ["param", "spam"] |
| assert docstring.meta[0].arg_name == "spam" |
| assert docstring.meta[0].description == "asd\n1\n 2\n3" |
|
|
|
|
| def test_default_args() -> None: |
| """Test parsing default arguments.""" |
| docstring = parse( |
| """A sample function |
| |
| A function the demonstrates docstrings |
| |
| Args: |
| arg1 (int): The firsty arg |
| arg2 (str): The second arg |
| arg3 (float, optional): The third arg. Defaults to 1.0. |
| arg4 (Optional[Dict[str, Any]], optional): The last arg. Defaults to None. |
| arg5 (str, optional): The fifth arg. Defaults to DEFAULT_ARG5. |
| |
| Returns: |
| Mapping[str, Any]: The args packed in a mapping |
| """ |
| ) |
| assert docstring is not None |
| assert len(docstring.params) == 5 |
|
|
| arg4 = docstring.params[3] |
| assert arg4.arg_name == "arg4" |
| assert arg4.is_optional |
| assert arg4.type_name == "Optional[Dict[str, Any]]" |
| assert arg4.default == "None" |
| assert arg4.description == "The last arg. Defaults to None." |
|
|
|
|
| def test_multiple_meta() -> None: |
| """Test parsing multiple meta.""" |
| docstring = parse( |
| """ |
| Short description |
| |
| Args: |
| spam: asd |
| 1 |
| 2 |
| 3 |
| |
| Raises: |
| bla: herp |
| yay: derp |
| """ |
| ) |
| assert docstring.short_description == "Short description" |
| assert len(docstring.meta) == 3 |
| assert docstring.meta[0].args == ["param", "spam"] |
| assert docstring.meta[0].arg_name == "spam" |
| assert docstring.meta[0].description == "asd\n1\n 2\n3" |
| assert docstring.meta[1].args == ["raises", "bla"] |
| assert docstring.meta[1].type_name == "bla" |
| assert docstring.meta[1].description == "herp" |
| assert docstring.meta[2].args == ["raises", "yay"] |
| assert docstring.meta[2].type_name == "yay" |
| assert docstring.meta[2].description == "derp" |
|
|
|
|
| def test_params() -> None: |
| """Test parsing params.""" |
| docstring = parse("Short description") |
| assert len(docstring.params) == 0 |
|
|
| docstring = parse( |
| """ |
| Short description |
| |
| Args: |
| name: description 1 |
| priority (int): description 2 |
| sender (str?): description 3 |
| ratio (Optional[float], optional): description 4 |
| """ |
| ) |
| assert len(docstring.params) == 4 |
| assert docstring.params[0].arg_name == "name" |
| assert docstring.params[0].type_name is None |
| assert docstring.params[0].description == "description 1" |
| assert not docstring.params[0].is_optional |
| assert docstring.params[1].arg_name == "priority" |
| assert docstring.params[1].type_name == "int" |
| assert docstring.params[1].description == "description 2" |
| assert not docstring.params[1].is_optional |
| assert docstring.params[2].arg_name == "sender" |
| assert docstring.params[2].type_name == "str" |
| assert docstring.params[2].description == "description 3" |
| assert docstring.params[2].is_optional |
| assert docstring.params[3].arg_name == "ratio" |
| assert docstring.params[3].type_name == "Optional[float]" |
| assert docstring.params[3].description == "description 4" |
| assert docstring.params[3].is_optional |
|
|
| docstring = parse( |
| """ |
| Short description |
| |
| Args: |
| name: description 1 |
| with multi-line text |
| priority (int): description 2 |
| """ |
| ) |
| assert len(docstring.params) == 2 |
| assert docstring.params[0].arg_name == "name" |
| assert docstring.params[0].type_name is None |
| assert docstring.params[0].description == ( |
| "description 1\nwith multi-line text" |
| ) |
| assert docstring.params[1].arg_name == "priority" |
| assert docstring.params[1].type_name == "int" |
| assert docstring.params[1].description == "description 2" |
|
|
|
|
| def test_attributes() -> None: |
| """Test parsing attributes.""" |
| docstring = parse("Short description") |
| assert len(docstring.params) == 0 |
|
|
| docstring = parse( |
| """ |
| Short description |
| |
| Attributes: |
| name: description 1 |
| priority (int): description 2 |
| sender (str?): description 3 |
| ratio (Optional[float], optional): description 4 |
| """ |
| ) |
| assert len(docstring.params) == 4 |
| assert docstring.params[0].arg_name == "name" |
| assert docstring.params[0].type_name is None |
| assert docstring.params[0].description == "description 1" |
| assert not docstring.params[0].is_optional |
| assert docstring.params[1].arg_name == "priority" |
| assert docstring.params[1].type_name == "int" |
| assert docstring.params[1].description == "description 2" |
| assert not docstring.params[1].is_optional |
| assert docstring.params[2].arg_name == "sender" |
| assert docstring.params[2].type_name == "str" |
| assert docstring.params[2].description == "description 3" |
| assert docstring.params[2].is_optional |
| assert docstring.params[3].arg_name == "ratio" |
| assert docstring.params[3].type_name == "Optional[float]" |
| assert docstring.params[3].description == "description 4" |
| assert docstring.params[3].is_optional |
|
|
| docstring = parse( |
| """ |
| Short description |
| |
| Attributes: |
| name: description 1 |
| with multi-line text |
| priority (int): description 2 |
| """ |
| ) |
| assert len(docstring.params) == 2 |
| assert docstring.params[0].arg_name == "name" |
| assert docstring.params[0].type_name is None |
| assert docstring.params[0].description == ( |
| "description 1\nwith multi-line text" |
| ) |
| assert docstring.params[1].arg_name == "priority" |
| assert docstring.params[1].type_name == "int" |
| assert docstring.params[1].description == "description 2" |
|
|
|
|
| def test_returns() -> None: |
| """Test parsing returns.""" |
| docstring = parse( |
| """ |
| Short description |
| """ |
| ) |
| assert docstring.returns is None |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 0 |
|
|
| docstring = parse( |
| """ |
| Short description |
| Returns: |
| description |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name is None |
| assert docstring.returns.description == "description" |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
| docstring = parse( |
| """ |
| Short description |
| Returns: |
| description with: a colon! |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name is None |
| assert docstring.returns.description == "description with: a colon!" |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
| docstring = parse( |
| """ |
| Short description |
| Returns: |
| int: description |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name == "int" |
| assert docstring.returns.description == "description" |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
| docstring = parse( |
| """ |
| Returns: |
| Optional[Mapping[str, List[int]]]: A description: with a colon |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name == "Optional[Mapping[str, List[int]]]" |
| assert docstring.returns.description == "A description: with a colon" |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
| docstring = parse( |
| """ |
| Short description |
| Yields: |
| int: description |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name == "int" |
| assert docstring.returns.description == "description" |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
| docstring = parse( |
| """ |
| Short description |
| Returns: |
| int: description |
| with much text |
| |
| even some spacing |
| """ |
| ) |
| assert docstring.returns is not None |
| assert docstring.returns.type_name == "int" |
| assert docstring.returns.description == ( |
| "description\nwith much text\n\neven some spacing" |
| ) |
| assert docstring.many_returns is not None |
| assert len(docstring.many_returns) == 1 |
| assert docstring.many_returns[0] == docstring.returns |
|
|
|
|
| def test_raises() -> None: |
| """Test parsing raises.""" |
| docstring = parse( |
| """ |
| Short description |
| """ |
| ) |
| assert len(docstring.raises) == 0 |
|
|
| docstring = parse( |
| """ |
| Short description |
| Raises: |
| ValueError: description |
| """ |
| ) |
| assert len(docstring.raises) == 1 |
| assert docstring.raises[0].type_name == "ValueError" |
| assert docstring.raises[0].description == "description" |
|
|
|
|
| def test_examples() -> None: |
| """Test parsing examples.""" |
| docstring = parse( |
| """ |
| Short description |
| Example: |
| example: 1 |
| Examples: |
| long example |
| |
| more here |
| """ |
| ) |
| assert len(docstring.examples) == 2 |
| assert docstring.examples[0].description == "example: 1" |
| assert docstring.examples[1].description == "long example\n\nmore here" |
|
|
|
|
| def test_broken_meta() -> None: |
| """Test parsing broken meta.""" |
| with pytest.raises(ParseError): |
| parse("Args:") |
|
|
| with pytest.raises(ParseError): |
| parse("Args:\n herp derp") |
|
|
|
|
| def test_unknown_meta() -> None: |
| """Test parsing unknown meta.""" |
| docstring = parse( |
| """Short desc |
| |
| Unknown 0: |
| title0: content0 |
| |
| Args: |
| arg0: desc0 |
| arg1: desc1 |
| |
| Unknown1: |
| title1: content1 |
| |
| Unknown2: |
| title2: content2 |
| """ |
| ) |
|
|
| assert docstring.params[0].arg_name == "arg0" |
| assert docstring.params[0].description == "desc0" |
| assert docstring.params[1].arg_name == "arg1" |
| assert docstring.params[1].description == "desc1" |
|
|
|
|
| def test_broken_arguments() -> None: |
| """Test parsing broken arguments.""" |
| with pytest.raises(ParseError): |
| parse( |
| """This is a test |
| |
| Args: |
| param - poorly formatted |
| """ |
| ) |
|
|
|
|
| def test_empty_example() -> None: |
| """Test parsing empty examples section.""" |
| docstring = parse( |
| """Short description |
| |
| Example: |
| |
| Raises: |
| IOError: some error |
| """ |
| ) |
|
|
| assert len(docstring.examples) == 1 |
| assert docstring.examples[0].args == ["examples"] |
| assert docstring.examples[0].description == "" |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected", |
| [ |
| ("", ""), |
| ("\n", ""), |
| ("Short description", "Short description"), |
| ("\nShort description\n", "Short description"), |
| ("\n Short description\n", "Short description"), |
| ( |
| "Short description\n\nLong description", |
| "Short description\n\nLong description", |
| ), |
| ( |
| """ |
| Short description |
| |
| Long description |
| """, |
| "Short description\n\nLong description", |
| ), |
| ( |
| """ |
| Short description |
| |
| Long description |
| Second line |
| """, |
| "Short description\n\nLong description\nSecond line", |
| ), |
| ( |
| "Short description\nLong description", |
| "Short description\nLong description", |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| """, |
| "Short description\nLong description", |
| ), |
| ( |
| "\nShort description\nLong description\n", |
| "Short description\nLong description", |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| Second line |
| """, |
| "Short description\nLong description\nSecond line", |
| ), |
| ( |
| """ |
| Short description |
| Meta: |
| asd |
| """, |
| "Short description\nMeta:\n asd", |
| ), |
| ( |
| """ |
| Short description |
| Long description |
| Meta: |
| asd |
| """, |
| "Short description\nLong description\nMeta:\n asd", |
| ), |
| ( |
| """ |
| Short description |
| First line |
| Second line |
| Meta: |
| asd |
| """, |
| "Short description\n" |
| "First line\n" |
| " Second line\n" |
| "Meta:\n" |
| " asd", |
| ), |
| ( |
| """ |
| Short description |
| |
| First line |
| Second line |
| Meta: |
| asd |
| """, |
| "Short description\n" |
| "\n" |
| "First line\n" |
| " Second line\n" |
| "Meta:\n" |
| " asd", |
| ), |
| ( |
| """ |
| Short description |
| |
| First line |
| Second line |
| |
| Meta: |
| asd |
| """, |
| "Short description\n" |
| "\n" |
| "First line\n" |
| " Second line\n" |
| "\n" |
| "Meta:\n" |
| " asd", |
| ), |
| ( |
| """ |
| Short description |
| |
| Meta: |
| asd |
| 1 |
| 2 |
| 3 |
| """, |
| "Short description\n" |
| "\n" |
| "Meta:\n" |
| " asd\n" |
| " 1\n" |
| " 2\n" |
| " 3", |
| ), |
| ( |
| """ |
| Short description |
| |
| Meta1: |
| asd |
| 1 |
| 2 |
| 3 |
| Meta2: |
| herp |
| Meta3: |
| derp |
| """, |
| "Short description\n" |
| "\n" |
| "Meta1:\n" |
| " asd\n" |
| " 1\n" |
| " 2\n" |
| " 3\n" |
| "Meta2:\n" |
| " herp\n" |
| "Meta3:\n" |
| " derp", |
| ), |
| ( |
| """ |
| Short description |
| |
| Args: |
| name: description 1 |
| priority (int): description 2 |
| sender (str, optional): description 3 |
| message (str, optional): description 4, defaults to 'hello' |
| multiline (str?): |
| long description 5, |
| defaults to 'bye' |
| """, |
| "Short description\n" |
| "\n" |
| "Args:\n" |
| " name: description 1\n" |
| " priority (int): description 2\n" |
| " sender (str?): description 3\n" |
| " message (str?): description 4, defaults to 'hello'\n" |
| " multiline (str?): long description 5,\n" |
| " defaults to 'bye'", |
| ), |
| ( |
| """ |
| Short description |
| Raises: |
| ValueError: description |
| """, |
| "Short description\nRaises:\n ValueError: description", |
| ), |
| ], |
| ) |
| def test_compose(source: str, expected: str) -> None: |
| """Test compose in default mode.""" |
| assert compose(parse(source)) == expected |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected", |
| [ |
| ( |
| """ |
| Short description |
| |
| Args: |
| name: description 1 |
| priority (int): description 2 |
| sender (str, optional): description 3 |
| message (str, optional): description 4, defaults to 'hello' |
| multiline (str?): |
| long description 5, |
| defaults to 'bye' |
| """, |
| "Short description\n" |
| "\n" |
| "Args:\n" |
| " name: description 1\n" |
| " priority (int): description 2\n" |
| " sender (str, optional): description 3\n" |
| " message (str, optional): description 4, defaults to 'hello'\n" |
| " multiline (str, optional): long description 5,\n" |
| " defaults to 'bye'", |
| ), |
| ], |
| ) |
| def test_compose_clean(source: str, expected: str) -> None: |
| """Test compose in clean mode.""" |
| assert ( |
| compose(parse(source), rendering_style=RenderingStyle.CLEAN) |
| == expected |
| ) |
|
|
|
|
| @pytest.mark.parametrize( |
| "source, expected", |
| [ |
| ( |
| """ |
| Short description |
| |
| Args: |
| name: description 1 |
| priority (int): description 2 |
| sender (str, optional): description 3 |
| message (str, optional): description 4, defaults to 'hello' |
| multiline (str?): |
| long description 5, |
| defaults to 'bye' |
| """, |
| "Short description\n" |
| "\n" |
| "Args:\n" |
| " name:\n" |
| " description 1\n" |
| " priority (int):\n" |
| " description 2\n" |
| " sender (str, optional):\n" |
| " description 3\n" |
| " message (str, optional):\n" |
| " description 4, defaults to 'hello'\n" |
| " multiline (str, optional):\n" |
| " long description 5,\n" |
| " defaults to 'bye'", |
| ), |
| ], |
| ) |
| def test_compose_expanded(source: str, expected: str) -> None: |
| """Test compose in expanded mode.""" |
| assert ( |
| compose(parse(source), rendering_style=RenderingStyle.EXPANDED) |
| == expected |
| ) |
|
|