diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md new file mode 100644 index 0000000..02778d0 --- /dev/null +++ b/CONTRIBUTION.md @@ -0,0 +1,29 @@ +# Contribution Guidelines + +Thank you for your interest in contributing to our Poetry Project! We welcome all contributions and appreciate your effort. Here are the guidelines for contributing: + +## Reporting Issues + +If you find any bugs or issues, please report them in the issue tracker. Be sure to include details about the issue and steps to reproduce it. + +## Submitting Changes + +1. Fork the repository. +2. Create a new branch for your changes. +3. Make your changes in your branch. +4. Submit a pull request with your changes. +5. Ensure your pull request passes all tests. + +## Code of Conduct + +We expect all contributors to follow our Code of Conduct. Please review it before contributing. + +## Writing Poetry + +When writing poetry, please ensure it is original work. We welcome all styles and themes of poetry. + +## Review Process + +Once your pull request is submitted, a maintainer will review it. They may ask for changes or clarification. Once your pull request is approved, it will be merged into the main branch. + +Thank you for your contribution! \ No newline at end of file diff --git a/PyDocSmith/common.py b/PyDocSmith/common.py index 360b639..6e002c0 100644 --- a/PyDocSmith/common.py +++ b/PyDocSmith/common.py @@ -1,5 +1,6 @@ """Common methods for parsing.""" import enum +import textwrap import typing as T PARAM_KEYWORDS = { @@ -177,7 +178,7 @@ def __init__( self.long_description = None # type: T.Optional[str] self.blank_after_short_description = False self.blank_after_long_description = False - self.meta = [] # type: T.List[DocstringMeta] + self.meta: T.List[DocstringMeta] = [] # type: T.List[DocstringMeta] self.style = style # type: T.Optional[DocstringStyle] @property @@ -231,3 +232,20 @@ def examples(self) -> T.List[DocstringExample]: def notes(self) -> T.List[DocstringNote]: """Return a list of information on function notes.""" return [item for item in self.meta if isinstance(item, DocstringNote)] + +def format_docstring_to_pep257(docstring: Docstring, width: int = 72) -> Docstring: + if docstring.short_description: + docstring.short_description = textwrap.fill(docstring.short_description.strip(), width) + if docstring.long_description: + docstring.long_description = textwrap.fill(docstring.long_description.strip(), width) + + for meta in docstring.meta: + if meta.description: + # Ensure meta descriptions are wrapped according to PEP 8 + meta.description = textwrap.fill(meta.description.strip(), width) + if meta.args: + # Clean up args to ensure they are stripped of extra spaces + meta.args = [arg.strip() for arg in meta.args if arg.strip()] + + return docstring + diff --git a/PyDocSmith/parser.py b/PyDocSmith/parser.py index dd9bd72..fb01b95 100644 --- a/PyDocSmith/parser.py +++ b/PyDocSmith/parser.py @@ -10,6 +10,7 @@ DocstringStyle, ParseError, RenderingStyle, + format_docstring_to_pep257, ) _STYLE_MAP = { @@ -116,6 +117,7 @@ def compose( style: DocstringStyle = DocstringStyle.AUTO, rendering_style: RenderingStyle = RenderingStyle.COMPACT, indent: str = " ", + line_width: int = 72 ) -> str: """Render a parsed docstring into docstring text. @@ -127,6 +129,10 @@ def compose( module = _STYLE_MAP[ docstring.style if style == DocstringStyle.AUTO else style ] + + if line_width >= 72: + docstring = format_docstring_to_pep257(docstring, width=line_width) + return module.compose( docstring, rendering_style=rendering_style, indent=indent ) diff --git a/PyDocSmith/tests/test_google.py b/PyDocSmith/tests/test_google.py index fd9456c..6f878b6 100644 --- a/PyDocSmith/tests/test_google.py +++ b/PyDocSmith/tests/test_google.py @@ -3,7 +3,7 @@ import typing as T import pytest -from PyDocSmith.common import Docstring, ParseError, RenderingStyle +from PyDocSmith.common import Docstring, ParseError, RenderingStyle, format_docstring_to_pep257 from PyDocSmith.google import ( GoogleParser, Section, @@ -982,6 +982,35 @@ def test_unknown_meta() -> None: assert docstring.params[1].arg_name == "arg1" assert docstring.params[1].description == "desc1" +def test_very_long_content_for_format_docstring_to_pep257() -> None: + # currently failing + """Test parsing unknown meta. This is failing""" + docstring = parse( + """A sample function + + A function the demonstrates docstrings with very long content that should be wrapped to the next line. Additionally, the function has a very long description that should be wrapped to the next line. + + 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: + The args packed in a mapping + """ + ) + docstring = format_docstring_to_pep257(docstring) + + assert docstring.short_description == "A sample function" + assert docstring.long_description == 'A function the demonstrates docstrings with very long content that\nshould be wrapped to the next line. Additionally, the function has a\nvery long description that should be wrapped to the next line.' + + assert docstring.params[0].arg_name == "arg1" + assert docstring.params[0].description == "The firsty arg" + assert docstring.params[1].arg_name == "arg2" + assert docstring.params[1].description == "The second arg" + def test_unformatted_valid_docstring() -> None: """ @@ -1002,6 +1031,7 @@ def test_unformatted_valid_docstring() -> None: None """ ) + composed_docstring = compose(docstring) assert ( docstring.short_description == "Set the RPM controller for the object." )