diff --git a/poetry.lock b/poetry.lock index c1f1d42..27c76ec 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.4.3 and should not be changed by hand. [[package]] name = "colorama" @@ -143,6 +143,34 @@ files = [ [package.dependencies] pytest = ">=5.0" +[[package]] +name = "ruff" +version = "0.16.8" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.16.8-py3-none-linux_armv6l.whl", hash = "sha256:6ffbd6d87383c1edf5f6fa890f10200950240d7c1a16052a19a09d3a2307dd38"}, + {file = "ruff-0.16.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:42ed6b878ed61e3acca92f2730a17acff39286944ea82398544696366a6f925e"}, + {file = "ruff-0.16.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7ea781c7f2afba8c6a505ea0fb3f994020249e0c450635f5381286fea6b46170"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8efeae3bbe414a5efefda11a792dfb51ef90ac48d50c4830de2f644caf3e8659"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a79b795469fef7fc6e908b218eed2eb17332afd85031db6480dc864560e69b2"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fdc5563cdc50555e6fba39322850860e9267c1b3d12c26a74729d8604c3c812"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34508983c70665578dab88f5223d8e6228307e1135398ca8bfc8b7e9501e282b"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:644bb578569e0ffc575741232bd385dacdd6fbe123f1a729e7a225f54aa3957f"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15e7d226246961db9235098333caa13063906d3851136b84c2900b82f5daa1df"}, + {file = "ruff-0.16.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a2bf6bc3e9ebdd4449abc6f06cf64b98051a2c61cf94d2fe9596518c881f1a1e"}, + {file = "ruff-0.16.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ca111ba0849539165e9e59d2b442542f3c1e8060ebbdea82494f1ffbccb1e1f"}, + {file = "ruff-0.16.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:359a1e5b495448ee1e91018064382ebc86f90e8aac2fed222c7d0e4e8df85fd2"}, + {file = "ruff-0.16.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:59e8f5681349474110b24d62e93cfda6593f5fa3473446ca3705200cac1a08b9"}, + {file = "ruff-0.16.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:efa3e7a16d1baaa79957888dfdf8be9ef2e44db81cb032af06d76632ab59e773"}, + {file = "ruff-0.16.8-py3-none-win32.whl", hash = "sha256:55793ba85c69921e89be061426d91a78652d6e50317c962240922747a4eb713f"}, + {file = "ruff-0.16.8-py3-none-win_amd64.whl", hash = "sha256:a6b85621fd3c81e31fc5f5add09c9c078b430db3595ca632efafdec9e64ebfaa"}, + {file = "ruff-0.16.8-py3-none-win_arm64.whl", hash = "sha256:d075e820af612102ce217f07cc93e69f9490b10ec13ea85fa87bd03d996cef8a"}, + {file = "ruff-0.16.8.tar.gz", hash = "sha256:9247bf92b5f04d825c8639a4fe423ec2e4222acd9222e58412b0dab7e442798b"}, +] + [[package]] name = "tomli" version = "2.4.1" @@ -217,4 +245,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "c5fdfbbe6dbd3da1ba43276d267c57089584d9940904d4cd53d25ce9e9fcd1c9" +content-hash = "24c9a2d464f6c737eeae0a66f792fa23824c3960b7cc72a22fff1408f21ec812" diff --git a/pyproject.toml b/pyproject.toml index 1dbff9f..002725e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,22 @@ priority = "supplemental" [dependency-groups] dev = [ "pytest (>=9.1.1,<10.0.0)", - "pytest-expectdir (>=1.2.0,<2.0.0)" + "pytest-expectdir (>=1.2.0,<2.0.0)", + "ruff (>=0.16.8,<0.17.0)" ] + +[tool.ruff] +line-length = 79 +target-version = "py311" + +[tool.ruff.lint] +select = [ + "E", + "F", + "W", + "I", + "UP" +] + +[tool.ruff.format] +quote-style = "single" diff --git a/src/jcloud_docsgen/__main__.py b/src/jcloud_docsgen/__main__.py index 57403ce..7de7226 100644 --- a/src/jcloud_docsgen/__main__.py +++ b/src/jcloud_docsgen/__main__.py @@ -13,6 +13,7 @@ # limitations under the License. import sys + from .cli.cli import main if __name__ == '__main__': diff --git a/src/jcloud_docsgen/cli/__init__.py b/src/jcloud_docsgen/cli/__init__.py index f1ada26..0008773 100644 --- a/src/jcloud_docsgen/cli/__init__.py +++ b/src/jcloud_docsgen/cli/__init__.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from . import cli -from . import languages +from . import cli, languages from .cli import main __all__ = [ diff --git a/src/jcloud_docsgen/cli/cli.py b/src/jcloud_docsgen/cli/cli.py index 4205064..ae22588 100644 --- a/src/jcloud_docsgen/cli/cli.py +++ b/src/jcloud_docsgen/cli/cli.py @@ -12,13 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' +""" The command line interface -''' +""" import argparse import pathlib import sys + from .languages.python import VALID_SECTIONS as VALID_PYTHON_SECTIONS __all__ = [ @@ -31,80 +32,81 @@ __all__ = [ _LANG_PYTHON = 'python' _PROGRAM_NAME = 'jcloud-docsgen' + def existing_directory(path: str) -> pathlib.Path: _path = path path = pathlib.Path(_path) if not path.exists(): - raise argparse.ArgumentTypeError( - f'{_path}: no such file or directory' - ) + raise argparse.ArgumentTypeError(f'{_path}: no such file or directory') if not path.is_dir(): raise argparse.ArgumentTypeError(f'{_path}: not a directory') return path + def error(message: str, exit_code: int = 1): - ''' + """ Shows an error message and returns the exit code. :param message: The error message to show. :type message: str :param exit_code: The exit code. :type exit_code: int - ''' + """ - print(f'{_PROGRAM_NAME}: error: {message}', file = sys.stderr) + print(f'{_PROGRAM_NAME}: error: {message}', file=sys.stderr) return exit_code + def create_argument_parser() -> argparse.ArgumentParser: - ''' + """ Prepares a parser to parse the command-line arguments using argparse. :return: The parser. :rtype: argparse.ArgumentParser - ''' + """ - common_parser = argparse.ArgumentParser(add_help = False) + common_parser = argparse.ArgumentParser(add_help=False) common_parser.add_argument( 'project_directory', - type = existing_directory, - nargs = '?', - default = pathlib.Path('.'), - help = 'The directory of the project', + type=existing_directory, + nargs='?', + default=pathlib.Path('.'), + help='The directory of the project', ) common_parser.add_argument( '-o', '--output-dir', - type = pathlib.Path, - help = 'the output directory the documentation will be written to', + type=pathlib.Path, + help='the output directory the documentation will be written to', ) argument_parser = argparse.ArgumentParser() subparsers = argument_parser.add_subparsers( - dest = 'language', - required = True, + dest='language', + required=True, ) python_parser = subparsers.add_parser( _LANG_PYTHON, - parents = [common_parser], - help = 'generate documentation for Python project', + parents=[common_parser], + help='generate documentation for Python project', ) python_parser.add_argument( '-s', '--sections', - nargs = '+', - choices = VALID_PYTHON_SECTIONS, - help = 'the sections to be included in the documentation', + nargs='+', + choices=VALID_PYTHON_SECTIONS, + help='the sections to be included in the documentation', ) python_parser.add_argument( '-S', '--sections-exclude', - nargs = '+', - default = [], - choices = VALID_PYTHON_SECTIONS, - help = ( + nargs='+', + default=[], + choices=VALID_PYTHON_SECTIONS, + help=( 'the sections to be excluded in the documentation. ' 'If a section shall be included AND excluded, it is excluded.' ), @@ -112,8 +114,8 @@ def create_argument_parser() -> argparse.ArgumentParser: python_parser.add_argument( '-H', '--allow-html', - action = 'store_true', - help = ( + action='store_true', + help=( 'indicates whether HTML is allowed in the documentation. ' 'By default, HTML is disabled.' ), @@ -121,8 +123,8 @@ def create_argument_parser() -> argparse.ArgumentParser: python_parser.add_argument( '-T', '--allow-tables', - action = 'store_true', - help = ( + action='store_true', + help=( 'indicates whether Markdown tables are allowed in the ' 'documentation. By default, Markdown tables are disabled. ' 'Warning: Markdown tables are not CommonMark.' @@ -131,7 +133,8 @@ def create_argument_parser() -> argparse.ArgumentParser: return argument_parser -def main(argv = None) -> int: + +def main(argv=None) -> int: argument_parser = create_argument_parser() args = argument_parser.parse_args(argv) @@ -141,13 +144,14 @@ def main(argv = None) -> int: try: if args.language == _LANG_PYTHON: from .languages.python import generate + generate( args.project_directory, args.output_dir, - include_sections = args.sections, - exclude_sections = args.sections_exclude, - allow_html = args.allow_html, - allow_tables = args.allow_tables, + include_sections=args.sections, + exclude_sections=args.sections_exclude, + allow_html=args.allow_html, + allow_tables=args.allow_tables, ) except FileNotFoundError as exc: return error(f'{exc.filename}: no such file or directory') @@ -166,7 +170,7 @@ def main(argv = None) -> int: except SyntaxError: # TODO: add a custom exception class to clearify that a project # parsing syntax error is meant. - return error(f'syntax error in project source code') + return error('syntax error in project source code') except KeyboardInterrupt: return 130 except BrokenPipeError: diff --git a/src/jcloud_docsgen/cli/languages/python.py b/src/jcloud_docsgen/cli/languages/python.py index ab4bbce..ae74fe9 100644 --- a/src/jcloud_docsgen/cli/languages/python.py +++ b/src/jcloud_docsgen/cli/languages/python.py @@ -13,11 +13,11 @@ # limitations under the License. import pathlib + from ...core.python import ( PythonDefinitionDocumentationIncludeSections, PythonDocumentationGenerator, ) -from typing import Optional __all__ = [ 'VALID_SECTIONS', @@ -29,24 +29,25 @@ VALID_SECTIONS = list( PythonDefinitionDocumentationIncludeSections()._args.keys() ) + def parse_sections_list( - include_sections: Optional[list[str]] = None, + include_sections: list[str] | None = None, exclude_sections: list[str] = [], ) -> PythonDefinitionDocumentationIncludeSections: - ''' + """ Returns a Python definition documentation sections list from the sections list to be included and the sections list to be excluded. These lists both consist of the sections as strings which contain the section name. :param include_sections: The list of sections to be included. - :type include_sections: Optional[list[str]] + :type include_sections: list[str] | None :param exclude_sections: The list of sections to be excluded. :type exclude_sections: list[str] :return: The Python definition documentation sections object. :rtype: PythonDefinitionDocumentationIncludeSections - ''' + """ if include_sections is None: include_sections = VALID_SECTIONS[:] @@ -56,17 +57,18 @@ def parse_sections_list( del include_sections[include_sections.index(section)] return PythonDefinitionDocumentationIncludeSections( - signature = 'signature' in include_sections, - returns = 'returns' in include_sections, - params = 'params' in include_sections, - exceptions = 'exceptions' in include_sections, - examples = 'examples' in include_sections, - docstring = 'docstring' in include_sections, - bases = 'bases' in include_sections, - decorators = 'decorators' in include_sections, - class_body = 'class_body' in include_sections, + signature='signature' in include_sections, + returns='returns' in include_sections, + params='params' in include_sections, + exceptions='exceptions' in include_sections, + examples='examples' in include_sections, + docstring='docstring' in include_sections, + bases='bases' in include_sections, + decorators='decorators' in include_sections, + class_body='class_body' in include_sections, ) + def _generate( project_directory: pathlib.Path, output_directory: pathlib.Path, @@ -77,7 +79,7 @@ def _generate( allow_html: bool = False, allow_tables: bool = False, ) -> None: - ''' + """ Generates the documentation for a Python project. :param project_directory: The project directory. @@ -92,27 +94,28 @@ def _generate( :type allow_html: bool :param allow_tables: Indicates whether Markdown tables are allowed. Warning: Markdown tables are not CommonMark. - ''' + """ docs_generator = PythonDocumentationGenerator( project_directory, output_directory, - include_sections = include_sections, - allow_html = allow_html, - allow_tables = allow_tables, + include_sections=include_sections, + allow_html=allow_html, + allow_tables=allow_tables, ) docs_generator.generate_documentation() + def generate( project_directory: pathlib.Path, output_directory: pathlib.Path, *, - include_sections: Optional[list[str]] = None, + include_sections: list[str] | None = None, exclude_sections: list[str] = [], allow_html: bool = False, allow_tables: bool = False, ) -> None: - ''' + """ Generates the documentation for a Python project. :param project_directory: The project directory. @@ -121,7 +124,7 @@ def generate( :type output_directory: pathlib.Path :param include_sections: The sections to be included in the documentation. - :type include_sections: Optional[list[str]] + :type include_sections: list[str] | None :param exclude_sections: The sections to be excluded in the documentation. :type exclude_sections: list[str] @@ -130,14 +133,14 @@ def generate( :type allow_html: bool :param allow_tables: Indicates whether Markdown tables are allowed. Warning: Markdown tables are not CommonMark. - ''' + """ sections = parse_sections_list(include_sections, exclude_sections) _generate( project_directory, output_directory, - include_sections = sections, - allow_html = allow_html, - allow_tables = allow_tables, + include_sections=sections, + allow_html=allow_html, + allow_tables=allow_tables, ) diff --git a/src/jcloud_docsgen/core/python/__init__.py b/src/jcloud_docsgen/core/python/__init__.py index 89ef350..1213677 100644 --- a/src/jcloud_docsgen/core/python/__init__.py +++ b/src/jcloud_docsgen/core/python/__init__.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from . import namespaces from ._core import * from ._core import __all__ as _core__all__ -from . import namespaces __all__ = [ *_core__all__, diff --git a/src/jcloud_docsgen/core/python/_core.py b/src/jcloud_docsgen/core/python/_core.py index cf4ba2c..b948125 100644 --- a/src/jcloud_docsgen/core/python/_core.py +++ b/src/jcloud_docsgen/core/python/_core.py @@ -13,25 +13,26 @@ # limitations under the License. from __future__ import annotations -from ...utils import non_empty_str, get_relative_path_segments -from ...exceptions import PythonArgumentStructureError, InvalidNamespaceError -from .namespaces import PythonModuleNamespace, PythonPackageNamespace + +import ast +import pathlib +from collections.abc import Iterator +from dataclasses import dataclass +from typing import TypeAlias + +import docstring_parser + +from ...exceptions import InvalidNamespaceError, PythonArgumentStructureError +from ...utils import get_relative_path_segments, non_empty_str +from .arguments import PythonArgumentKind, PythonFunctionArgument from .definitions import ( PythonAsyncFunctionDefinition, PythonClassDefinition, PythonDefinition, PythonFunctionDefinition, ) -from .arguments import PythonArgumentKind, PythonFunctionArgument from .docstrings import PythonDocstring -from collections.abc import Iterator -from typing import TypeAlias, Union -from dataclasses import dataclass -from enum import Enum -import docstring_parser -import pathlib -import ast -import types +from .namespaces import PythonModuleNamespace, PythonPackageNamespace __all__ = [ 'PythonDefinitionDocumentationIncludeSections', @@ -40,15 +41,16 @@ __all__ = [ 'PythonDocumentationGenerator', ] + def _collect_definitions(tree_or_node) -> Iterator[PythonDefinition]: - ''' + """ Collects all definitions of the tree or node. :param tree_or_node: The tree or node. :return: The definitions. :rtype: Iterator[PythonDefinition] - ''' + """ for node in tree_or_node.body: if isinstance(node, ast.FunctionDef): @@ -58,18 +60,20 @@ def _collect_definitions(tree_or_node) -> Iterator[PythonDefinition]: if isinstance(node, ast.ClassDef): yield PythonClassDefinition.from_node(node) + _Arguments: TypeAlias = tuple[ list[PythonFunctionArgument], list[PythonFunctionArgument], - Union[PythonFunctionArgument, None], + PythonFunctionArgument | None, list[PythonFunctionArgument], - Union[PythonFunctionArgument, None], + PythonFunctionArgument | None, ] + def _group_argument_list( argument_list: list[PythonFunctionArgument], ) -> _Arguments: - ''' + """ Groups the argument list into a list of positional-only arguments, a list of normal arguments, the * argument if there is one, a list of keyword-only arguments and the var-keyword-argument if there is one. @@ -78,13 +82,12 @@ def _group_argument_list( :type argument_list: list[PythonFunctionArgument] :rtype: _Arguments - ''' + """ if argument_list: - if argument_list[-1].kind != PythonArgumentKind.KWARGS and any([ - arg.kind == PythonArgumentKind.KWARGS - for arg in argument_list - ]): + if argument_list[-1].kind != PythonArgumentKind.KWARGS and any( + [arg.kind == PythonArgumentKind.KWARGS for arg in argument_list] + ): raise PythonArgumentStructureError( 'arguments cannot follow var-keyword argument', ) @@ -106,7 +109,7 @@ def _group_argument_list( if vararg is not None: raise PythonArgumentStructureError( '* argument may only appear once', - definition = arg, + definition=arg, ) vararg = arg @@ -124,10 +127,11 @@ def _group_argument_list( kwargs, ) + def _signature_argument_list( argument_list: list[PythonFunctionArgument], ) -> list[str]: - ''' + """ Returns a list of the arguments as strings for a function signature. :param argument_list: The argument list. @@ -135,7 +139,7 @@ def _signature_argument_list( :return: The list of function signature argument strings. :rtype: list[str] - ''' + """ ( positional_only_args, @@ -170,8 +174,9 @@ def _signature_argument_list( return args + def _fit_row_length(expected: int, row: tuple) -> tuple: - ''' + """ Fits the row length to the expected length. If the row is too long, the tail, that makes it too long, is omitted. @@ -181,7 +186,7 @@ def _fit_row_length(expected: int, row: tuple) -> tuple: :type expected: int :param row: The row. :type row: tuple - ''' + """ if expected < 0: raise ValueError('expected must be larger than or equal 0.') @@ -191,6 +196,7 @@ def _fit_row_length(expected: int, row: tuple) -> tuple: else: return row + (None,) * (expected - len(row)) + def _markdown_table( header: tuple, body: list[tuple], @@ -200,7 +206,7 @@ def _markdown_table( one_line_values: bool = True, missing_value: str = '--', ) -> str: - ''' + """ Generates a table. If ``allow_markdown_table`` is ``False``, an alternative @@ -222,7 +228,7 @@ def _markdown_table( :param missing_value: The string that is used if a value is missing (only if ``force_row_lengths`` is ``False``). :type missing_value: str - ''' + """ if not header or not body: return '' @@ -231,37 +237,34 @@ def _markdown_table( if allow_markdown_table: table = ( - '| ' \ - + ' | '.join(header) \ - + ' |\n|' \ - + ' --- |' * len(header) \ - + '\n' + '| ' + ' | '.join(header) + ' |\n|' + ' --- |' * len(header) + '\n' ) - for row in body: if len(row) != header_len: if force_row_lengths: raise ValueError( f'expected {header_len} value{ - "s" - if header_len > 1 - else "" + "s" if header_len > 1 else "" }, got {len(row)}', ) else: row = _fit_row_length(header_len, row) - table += '| ' + ' | '.join([ - str( - col - if col is not None - else missing_value - ).replace('\n', ' ') - if one_line_values - else str(col if col is not None else missing_value) - for col in row - ]) + ' |\n' + table += ( + '| ' + + ' | '.join( + [ + str(col if col is not None else missing_value).replace( + '\n', ' ' + ) + if one_line_values + else str(col if col is not None else missing_value) + for col in row + ] + ) + + ' |\n' + ) else: table = '' @@ -270,9 +273,7 @@ def _markdown_table( if force_row_lengths: raise ValueError( f'expected {header_len} value{ - "s" - if header_len > 1 - else "" + "s" if header_len > 1 else "" }, got {len(row)}', ) else: @@ -281,37 +282,33 @@ def _markdown_table( sep = '- ' for i, col in enumerate(row): table += ( - sep \ - + header[i] \ - + ': ' \ + sep + + header[i] + + ': ' + ( - str( - col - if col is not None - else missing_value - ).replace('\n', ' ') \ - if one_line_values \ - else str( - col - if col is not None - else missing_value + str(col if col is not None else missing_value).replace( + '\n', ' ' ) - ) + '\n\n' + if one_line_values + else str(col if col is not None else missing_value) + ) + + '\n\n' ) sep = ' ' return table.strip() -def _is_docstring(docstring: Union[str, PythonDocstring, None]) -> bool: - ''' + +def _is_docstring(docstring: str | PythonDocstring | None) -> bool: + """ Checks whether the docstring is a docstring or an empty docstring. :param docstring: The docstring. - :type docstring: Union[str, PythonDocstring, None] + :type docstring: str | PythonDocstring | None :return: Whether there is a docstring. :rtype: bool - ''' + """ if docstring is None: return False @@ -321,10 +318,12 @@ def _is_docstring(docstring: Union[str, PythonDocstring, None]) -> bool: return docstring.strip() != '' + @dataclass class _FunctionParamInfo: - annotation: Union[str, None] - description: Union[str, None] + annotation: str | None + description: str | None + @dataclass class _NoDocstringTemplate: @@ -340,10 +339,12 @@ class _NoDocstringTemplate: long_description = None blank_after_short_description = None + _NoDocstring = _NoDocstringTemplate() + def _argument_kind_human_readable(argument_kind: PythonArgumentKind) -> str: - ''' + """ Returns the human-readable representation of a ``PythonArgumentKind``. @@ -352,15 +353,16 @@ def _argument_kind_human_readable(argument_kind: PythonArgumentKind) -> str: :return: The human-readable representation. :rtype: str - ''' + """ return argument_kind.name.lower().replace('_', '-') + def _function_params_info( arg_list: list[PythonFunctionArgument], docstring_arg_list: list[docstring_parser.DocstringParam], ) -> dict[str, _FunctionParamInfo]: - ''' + """ Returns a dictionary with the parameter info. The keys of the dictionary are the parameter names and the values are @@ -377,11 +379,10 @@ def _function_params_info( :return: The dictionary with the parameter types. :rtype: dict[str, _FunctionParamInfo] - ''' + """ arg_annotations = { - arg.name: _FunctionParamInfo(arg.annotation, None) - for arg in arg_list + arg.name: _FunctionParamInfo(arg.annotation, None) for arg in arg_list } for arg in docstring_arg_list: @@ -393,8 +394,9 @@ def _function_params_info( return arg_annotations + class PythonDefinitionDocumentationIncludeSections: - ''' + """ A class representing the included sections in a Python definition documentation. @@ -414,50 +416,55 @@ class PythonDefinitionDocumentationIncludeSections: :type bases: bool :param decorators: Whether include the decorators section. :type decorators: bool - ''' + """ def __init__( - self, - *, - signature: bool = True, - returns: bool = True, - params: bool = True, - exceptions: bool = True, - examples: bool = True, - docstring: bool = True, - bases: bool = True, - decorators: bool = True, - class_body: bool = True, - ): - self.signature = signature - self.returns = returns - self.params = params - self.exceptions = exceptions - self.examples = examples - self.docstring = docstring - self.bases = bases - self.decorators = decorators - self.class_body = class_body + self, + *, + signature: bool = True, + returns: bool = True, + params: bool = True, + exceptions: bool = True, + examples: bool = True, + docstring: bool = True, + bases: bool = True, + decorators: bool = True, + class_body: bool = True, + ): + self.signature = signature + self.returns = returns + self.params = params + self.exceptions = exceptions + self.examples = examples + self.docstring = docstring + self.bases = bases + self.decorators = decorators + self.class_body = class_body - self._args = { - 'signature': self.signature, - 'returns': self.returns, - 'params': self.params, - 'exceptions': self.exceptions, - 'examples': self.examples, - 'docstring': self.docstring, - 'bases': self.bases, - 'decorators': self.decorators, - 'class_body': self.class_body, - } + self._args = { + 'signature': self.signature, + 'returns': self.returns, + 'params': self.params, + 'exceptions': self.exceptions, + 'examples': self.examples, + 'docstring': self.docstring, + 'bases': self.bases, + 'decorators': self.decorators, + 'class_body': self.class_body, + } def __repr__(self) -> str: - return type(self).__name__+ '(' + ', '.join( - [ - key + ' = ' + repr(value) - for key, value in self._args.items() - ], - ) + ')' + return ( + type(self).__name__ + + '(' + + ', '.join( + [ + key + ' = ' + repr(value) + for key, value in self._args.items() + ], + ) + + ')' + ) def __eq__(self, value) -> str: if not isinstance( @@ -467,8 +474,9 @@ class PythonDefinitionDocumentationIncludeSections: return False return self._args == value._args + class PythonDefinitionDocumentationGenerator: - ''' + """ A documentation generator for a Python definition. :param definition: The Python definition. @@ -492,21 +500,21 @@ class PythonDefinitionDocumentationGenerator: :type skip_empty_sections: bool :param is_method: Controls whether the definition is a class method. :type is_method: bool - ''' + """ def __init__( - self, - definition: PythonDefinition, - include_sections: PythonDefinitionDocumentationIncludeSections = ( - PythonDefinitionDocumentationIncludeSections() - ), - level: int = 1, - *, - allow_html: bool = True, - allow_tables: bool = False, - skip_empty_sections: bool = True, - is_method: bool = False, - ) -> None: + self, + definition: PythonDefinition, + include_sections: PythonDefinitionDocumentationIncludeSections = ( + PythonDefinitionDocumentationIncludeSections() + ), + level: int = 1, + *, + allow_html: bool = True, + allow_tables: bool = False, + skip_empty_sections: bool = True, + is_method: bool = False, + ) -> None: self.definition = definition self.include_sections = include_sections @@ -521,13 +529,15 @@ class PythonDefinitionDocumentationGenerator: @property def _docstring(self): if self._docstring_cache is None: - self._docstring_cache = self.definition.doc.parse() \ - if _is_docstring(self.definition.doc) \ + self._docstring_cache = ( + self.definition.doc.parse() + if _is_docstring(self.definition.doc) else _NoDocstring + ) return self._docstring_cache def generate_signature(self) -> str: - ''' + """ Generates the signature of the definition. Works only if the definition is a function or asynchronous function definition. @@ -535,18 +545,23 @@ class PythonDefinitionDocumentationGenerator: :return: The signature. :rtype: str - ''' + """ if isinstance(self.definition, PythonClassDefinition): raise TypeError( 'Cannot generate a signature of a class definition.', ) - signature = self.definition.name + '(' + ', '.join( - _signature_argument_list( - self.definition.args, - ), - ) + ')' + signature = ( + self.definition.name + + '(' + + ', '.join( + _signature_argument_list( + self.definition.args, + ), + ) + + ')' + ) if self.definition.returns is not None: signature += ' -> ' + self.definition.returns @@ -554,38 +569,38 @@ class PythonDefinitionDocumentationGenerator: return signature.strip() def _generate_signature_section(self) -> str: - ''' + """ Generates the signature section. :return: The signature section. :rtype: str - ''' + """ definition_type = 'Function' if not self.is_method else 'Method' - heading = self.level * '#' + '# ' + (definition_type) +' signature' - return f'''{heading} + heading = self.level * '#' + '# ' + (definition_type) + ' signature' + return f"""{heading} ```python {self.generate_signature()} -```''' +```""" def _generate_docstring_section(self) -> str: - ''' + """ Generates the docstring section. :return: The docstring section. :rtype: str - ''' + """ md = '' if _is_docstring(self.definition.doc) or not self.skip_empty_sections: if self.allow_html: - md += f'
Docstring' + md += f'
Docstring' else: md += self.level * '#' + '# Docstring\n\n' @@ -602,12 +617,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_params_section(self) -> str: - ''' + """ Generates the parameters section. :return: The parameters section. :rtype: str - ''' + """ md = '' @@ -636,7 +651,7 @@ class PythonDefinitionDocumentationGenerator: ) for arg in self.definition.args ], - allow_markdown_table = self.allow_tables, + allow_markdown_table=self.allow_tables, ) md += '\n\n' @@ -647,12 +662,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_returns_section(self) -> str: - ''' + """ Generates the returns section. :return: The returns section. :rtype: str - ''' + """ md = '' @@ -686,12 +701,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_exceptions_section(self) -> str: - ''' + """ Generates the exceptions section. :return: The exceptions section. :rtype: str - ''' + """ md = '' @@ -699,26 +714,31 @@ class PythonDefinitionDocumentationGenerator: md += self.level * '#' + '# Exceptions\n\n' if self._docstring.raises: - md += _markdown_table(('Exception', 'Description'), [ - ( - ('`' + exception.type_name + '`') - if exception.type_name is not None - else None, non_empty_str(exception.description) - ) - for exception in self._docstring.raises - ], allow_markdown_table = self.allow_tables) + md += _markdown_table( + ('Exception', 'Description'), + [ + ( + ('`' + exception.type_name + '`') + if exception.type_name is not None + else None, + non_empty_str(exception.description), + ) + for exception in self._docstring.raises + ], + allow_markdown_table=self.allow_tables, + ) elif not self.skip_empty_sections: md += 'This function raises no exceptions.' return md.strip() def _generate_examples_section(self) -> str: - ''' + """ Generates the examples section. :return: The examples section. :rtype: str - ''' + """ md = '' @@ -727,9 +747,11 @@ class PythonDefinitionDocumentationGenerator: examples = [] for example in self._docstring.examples: - examples.append('```python\n' +\ - (example.snippet or example.description) + \ - '\n```') + examples.append( + '```python\n' + + (example.snippet or example.description) + + '\n```' + ) md += '\n\n---\n\n'.join(examples) if not self._docstring.examples and not self.skip_empty_sections: @@ -738,12 +760,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_decorators_section(self) -> str: - ''' + """ Generates the decorators section. :return: The decorators section. :rtype: str - ''' + """ md = '' @@ -759,12 +781,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_bases_section(self) -> str: - ''' + """ Generates the bases section. :return: The bases section. :rtype: str - ''' + """ md = '' @@ -780,12 +802,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def _generate_body_section(self) -> str: - ''' + """ Generates the body section. :return: The body section. :rtype: str - ''' + """ md = '' @@ -793,15 +815,18 @@ class PythonDefinitionDocumentationGenerator: md += self.level * '#' + '# Body\n\n' for method_or_class in self.definition.body: - md += PythonDefinitionDocumentationGenerator( - method_or_class, - self.include_sections, - level = self.level + 2, - allow_html = self.allow_html, - allow_tables = self.allow_tables, - skip_empty_sections = self.skip_empty_sections, - is_method = True, - ).generate_documentation() + '\n\n' + md += ( + PythonDefinitionDocumentationGenerator( + method_or_class, + self.include_sections, + level=self.level + 2, + allow_html=self.allow_html, + allow_tables=self.allow_tables, + skip_empty_sections=self.skip_empty_sections, + is_method=True, + ).generate_documentation() + + '\n\n' + ) if not self.definition.body and not self.skip_empty_sections: md += 'This class does not have a body.' @@ -809,12 +834,12 @@ class PythonDefinitionDocumentationGenerator: return md.strip() def generate_documentation(self) -> str: - ''' + """ Generates the documentation in the markdown format. :return: The documentation. :rtype: str - ''' + """ md = self.level * '#' + ' ' @@ -848,13 +873,13 @@ class PythonDefinitionDocumentationGenerator: md += self._generate_signature_section() + '\n\n' if self.include_sections.returns: - md += self._generate_returns_section() + '\n\n' + md += self._generate_returns_section() + '\n\n' if self.include_sections.params: - md += self._generate_params_section() + '\n\n' + md += self._generate_params_section() + '\n\n' if self.include_sections.exceptions: - md += self._generate_exceptions_section() + '\n\n' + md += self._generate_exceptions_section() + '\n\n' if isinstance(self.definition, PythonClassDefinition): if self.include_sections.bases: @@ -874,8 +899,9 @@ class PythonDefinitionDocumentationGenerator: return md.strip() + class PythonModuleDocumentationGenerator: - ''' + """ A documentation generator for a Python module. :param module_path: The path of the module file. @@ -883,25 +909,25 @@ class PythonModuleDocumentationGenerator: :param src_directory: The directory of the source code. It is optional and only used for making the module identifiers in the documentation relative. - :type src_directory: Union[pathlib.Path, None] + :type src_directory: pathlib.Path | None :param include_sections: The sections that will be included. :type include_sections: PythonDefinitionDocumentationIncludeSections :param kwargs: The options for ``PythonDefinitionDocumentationGenerator``. - ''' + """ def __init__( - self, - module_path: pathlib.Path, - src_directory: Union[pathlib.Path, None] = None, - include_sections: PythonDefinitionDocumentationIncludeSections = ( - PythonDefinitionDocumentationIncludeSections() - ), - **kwargs, - ) -> None: + self, + module_path: pathlib.Path, + src_directory: pathlib.Path | None = None, + include_sections: PythonDefinitionDocumentationIncludeSections = ( + PythonDefinitionDocumentationIncludeSections() + ), + **kwargs, + ) -> None: if module_path.name.count('.') > 1: raise InvalidNamespaceError( 'namespace identifier cannot contain more than one dot', - namespace_identifier = module_path.name, + namespace_identifier=module_path.name, ) self.module_path = pathlib.Path(str(module_path)) @@ -930,25 +956,24 @@ class PythonModuleDocumentationGenerator: return self._ast_cache def collect_definitions(self) -> Iterator[PythonDefinition]: - ''' + """ Collects all function and class definitions of the module. :return: All definitions of the module :rtype: Iterator[PythonDefinition] - ''' + """ tree = self._ast return _collect_definitions(tree) def generate_documentation(self) -> str: - ''' + """ Generates the documentation in the markdown format. :return: The documentation. :rtype: str - ''' - + """ md = '# Module `' @@ -973,26 +998,30 @@ class PythonModuleDocumentationGenerator: md += docstring + '\n\n' for definition in self.collect_definitions(): - md += PythonDefinitionDocumentationGenerator( - definition, - self.include_sections, - 2, - **self.kwargs, - ).generate_documentation() + '\n\n' + md += ( + PythonDefinitionDocumentationGenerator( + definition, + self.include_sections, + 2, + **self.kwargs, + ).generate_documentation() + + '\n\n' + ) return md.strip() + def _generate_package_namespace_documentation( - namespace: PythonPackageNamespace, - documentation_directory: pathlib.Path, - root_directory: pathlib.Path, - dir: pathlib.Path, - include_sections: PythonDefinitionDocumentationIncludeSections = ( - PythonDefinitionDocumentationIncludeSections() - ), - kwargs: dict = {}, - ) -> None: - ''' + namespace: PythonPackageNamespace, + documentation_directory: pathlib.Path, + root_directory: pathlib.Path, + dir: pathlib.Path, + include_sections: PythonDefinitionDocumentationIncludeSections = ( + PythonDefinitionDocumentationIncludeSections() + ), + kwargs: dict = {}, +) -> None: + """ Generates the documentation for a package namespace and writes it to the documentation directory. @@ -1007,19 +1036,20 @@ def _generate_package_namespace_documentation( :param include_sections: The sections to be included in the documentation. :type include_sections: PythonDefinitionDocumentationIncludeSections :param kwargs: The options for the documentation generator. - ''' + """ documentation_directory = pathlib.Path(str(documentation_directory)) for sub_namespace in namespace.sub_namespaces: if isinstance(sub_namespace, PythonPackageNamespace): - ( - documentation_directory / sub_namespace.name - ).mkdir(mode = 0o700, exist_ok = True) + (documentation_directory / sub_namespace.name).mkdir( + mode=0o700, exist_ok=True + ) _generate_package_namespace_documentation( sub_namespace, documentation_directory / sub_namespace.name, - root_directory, dir / sub_namespace.name, + root_directory, + dir / sub_namespace.name, include_sections, kwargs, ) @@ -1035,8 +1065,9 @@ def _generate_package_namespace_documentation( ).generate_documentation() ) + class PythonDocumentationGenerator: - ''' + """ The class for the documentation generator. :param project_directory: The directory of the project. @@ -1046,17 +1077,17 @@ class PythonDocumentationGenerator: :param include_sections: The sections to be included in the documentation. :type include_sections: PythonDefinitionDocumentationIncludeSections :param kwargs: The options for ``PythonDefinitionDocumentationGenerator``. - ''' + """ def __init__( - self, - project_directory: pathlib.Path, - docs_directory: pathlib.Path, - include_sections: PythonDefinitionDocumentationIncludeSections = ( - PythonDefinitionDocumentationIncludeSections() - ), - **kwargs, - ) -> None: + self, + project_directory: pathlib.Path, + docs_directory: pathlib.Path, + include_sections: PythonDefinitionDocumentationIncludeSections = ( + PythonDefinitionDocumentationIncludeSections() + ), + **kwargs, + ) -> None: self.project_directory = pathlib.Path(str(project_directory)) self.docs_directory = pathlib.Path(str(docs_directory)) self.include_sections = include_sections @@ -1074,25 +1105,24 @@ class PythonDocumentationGenerator: return namespace def namespace(self) -> list[PythonPackageNamespace]: - ''' + """ Returns the project as a namespace. :return: The project as a namespace. :rtype: list[PythonPackageNamespace] - ''' + """ src_dir = self.project_directory / 'src' return [ - self._namespace(dir) - for dir in src_dir.iterdir() if dir.is_dir() + self._namespace(dir) for dir in src_dir.iterdir() if dir.is_dir() ] def generate_documentation(self) -> None: - ''' + """ Generates the full project documentation and writes it to the documentation directory. - ''' + """ _generate_package_namespace_documentation( PythonPackageNamespace('src', self.namespace()), diff --git a/src/jcloud_docsgen/core/python/arguments.py b/src/jcloud_docsgen/core/python/arguments.py index 9140fd8..d993675 100644 --- a/src/jcloud_docsgen/core/python/arguments.py +++ b/src/jcloud_docsgen/core/python/arguments.py @@ -13,17 +13,18 @@ # limitations under the License. from __future__ import annotations -from enum import Enum -from typing import Union + import ast -from ...utils import assert_that_is_instance +import keyword +import types +from enum import Enum + from ...exceptions import ( InvalidPythonAnnotationError, InvalidPythonIdentifierError, PythonArgumentStructureError, ) -import keyword -import types +from ...utils import assert_that_is_instance __all__ = [ 'PythonArgumentKind', @@ -31,6 +32,7 @@ __all__ = [ 'PythonASTArgumentsListParser', ] + class PythonArgumentKind(Enum): NORMAL = 0 POSITIONAL_ONLY = 1 @@ -38,8 +40,9 @@ class PythonArgumentKind(Enum): VARARG = 3 KWARGS = 4 + class PythonFunctionArgument: - ''' + """ Represents an argument of a Python function. :param name: The name of the argument. @@ -47,17 +50,17 @@ class PythonFunctionArgument: :param kind: The kind of the argument. :type kind: ArgumentKind :param default: The default value of the argument. - :type default: Union[str, None] + :type default: str | None :param annotation: The type annotation of the argument. - :type annotation: Union[str, None] - ''' + :type annotation: str | None + """ def __init__( self, name: str, kind: PythonArgumentKind, - default: Union[str, None], - annotation: Union[str, None], + default: str | None, + annotation: str | None, ) -> None: assert_that_is_instance(name, str) assert_that_is_instance(kind, PythonArgumentKind) @@ -68,7 +71,7 @@ class PythonFunctionArgument: if not name or not name.isidentifier() or keyword.iskeyword(name): raise InvalidPythonIdentifierError( 'invalid identifier', - identifier = name, + identifier=name, ) # check whether the annotation is a valid annotation @@ -77,7 +80,7 @@ class PythonFunctionArgument: if annotation is not None and not annotation: raise InvalidPythonAnnotationError( 'invalid annotation', - annotation = annotation, + annotation=annotation, ) self.name = name @@ -85,13 +88,17 @@ class PythonFunctionArgument: self.default = default self.annotation = annotation - if self.kind in ( - PythonArgumentKind.VARARG, - PythonArgumentKind.KWARGS, - ) and self.default is not None: + if ( + self.kind + in ( + PythonArgumentKind.VARARG, + PythonArgumentKind.KWARGS, + ) + and self.default is not None + ): raise PythonArgumentStructureError( '* or ** arguments cannot have default values', - definition = self.signature_repr(), + definition=self.signature_repr(), ) def __eq__(self, value: PythonFunctionArgument) -> bool: @@ -105,20 +112,22 @@ class PythonFunctionArgument: ) def __repr__(self) -> str: - return type(self).__name__ + repr(( - self.name, - self.kind, - self.default, - self.annotation, - )) + return type(self).__name__ + repr( + ( + self.name, + self.kind, + self.default, + self.annotation, + ) + ) def signature_repr(self) -> str: - ''' + """ Returns the function signature representation of the argument. :return: The string representation of the argument. :rtype: str - ''' + """ if self.kind == PythonArgumentKind.KWARGS: str_repr = '**' @@ -137,48 +146,44 @@ class PythonFunctionArgument: return str_repr + class PythonASTArgumentsListParser: - ''' + """ A parser for making ``PythonFunctionArgument`` objects from an ``ast.arguments`` arguments list. :param ast_arguments_list: The ``ast.arguments`` arguments list. :type ast_arguments_list: ast.arguments - ''' + """ - def __init__(self, ast_arguments_list: ast.arguments) -> None: + def __init__(self, ast_arguments_list: ast.arguments) -> None: self.ast_arguments_list = ast_arguments_list def to_argument_list(self) -> list[PythonFunctionArgument]: - ''' + """ Converts the AST arguments list to a list of Python function argument objects. :return: The list of Python function argument objects. :rtype: list[PythonFunctionArgument] - ''' + """ defaults = ( [ None - for _ in range(len( - self.ast_arguments_list.posonlyargs + - self.ast_arguments_list.args + - self.ast_arguments_list.kwonlyargs - ) - len( - self.ast_arguments_list.defaults - ) - len( - self.ast_arguments_list.kw_defaults - )) + for _ in range( + len( + self.ast_arguments_list.posonlyargs + + self.ast_arguments_list.args + + self.ast_arguments_list.kwonlyargs + ) + - len(self.ast_arguments_list.defaults) + - len(self.ast_arguments_list.kw_defaults) + ) ] + + [ast.unparse(d) for d in self.ast_arguments_list.defaults] + [ - ast.unparse(d) - for d in self.ast_arguments_list.defaults - ] - + [ - ast.unparse(d) - if d is not None - else None + ast.unparse(d) if d is not None else None for d in self.ast_arguments_list.kw_defaults ] ) diff --git a/src/jcloud_docsgen/core/python/definitions.py b/src/jcloud_docsgen/core/python/definitions.py index f54a98a..923b80a 100644 --- a/src/jcloud_docsgen/core/python/definitions.py +++ b/src/jcloud_docsgen/core/python/definitions.py @@ -13,14 +13,15 @@ # limitations under the License. from __future__ import annotations -from typing import Union + import ast -from .arguments import PythonFunctionArgument, PythonASTArgumentsListParser -from .docstrings import PythonDocstring import keyword +import types + from ...exceptions import InvalidPythonIdentifierError from ...utils import assert_that_is_instance -import types +from .arguments import PythonASTArgumentsListParser, PythonFunctionArgument +from .docstrings import PythonDocstring __all__ = [ 'PythonDefinition', @@ -29,46 +30,48 @@ __all__ = [ 'PythonClassDefinition', ] -def _python_docstring(doc: Union[str, None]) -> Union[PythonDocstring, None]: - ''' + +def _python_docstring(doc: str | None) -> PythonDocstring | None: + """ Returns the PythonDocstring object if the docstring is a string and not ``None``. :param doc: The docstring. - :type doc: Union[str, None] + :type doc: str | None :return: The PythonDocstring object or ``None``. - :rtype: Union[PythonDocstring, None] - ''' + :rtype: PythonDocstring | None + """ return PythonDocstring(doc) if doc is not None else None + class PythonDefinition: - ''' + """ A base class for Python definition (a class, function or asynchronous function definition) classes. :param name: The name of the definition. :type name: str :param doc: The docstring. - :type doc: Union[PythonDocstring, None] + :type doc: PythonDocstring | None :param decorators: The definition decorators. :type decorators: list[str] :raises InvalidPythonIdentifierError: If the name is not a valid Python identifier. - ''' + """ def __init__( self, name: str, - doc: Union[PythonDocstring, None], + doc: PythonDocstring | None, decorators: list[str], ) -> None: if keyword.iskeyword(name) or not name.isidentifier() or not name: raise InvalidPythonIdentifierError( 'invalid identifier', - identifier = name, + identifier=name, ) assert_that_is_instance(doc, (PythonDocstring, types.NoneType)) @@ -89,12 +92,12 @@ class PythonDefinition: @classmethod def from_node(cls, node: ast.stmt) -> PythonDefinition: - ''' + """ From an AST node. :param node: The AST node. :type node: ast.stmt - ''' + """ return cls( node.name, @@ -107,8 +110,9 @@ class PythonDefinition: return False return self._arg_list() == value._arg_list() + class PythonFunctionDefinition(PythonDefinition): - ''' + """ A PythonDefinition subclass representing a Python function definition. @@ -117,22 +121,22 @@ class PythonFunctionDefinition(PythonDefinition): :param args: The arguments. :type args: list[PythonFunctionArgument] :param returns: The return type of the function or class. - :type returns: Union[str, None] + :type returns: str | None :param doc: The docstring. - :type doc: Union[PythonDocstring, None] + :type doc: PythonDocstring | None :param decorators: The definition decorators. :type decorators: list[str] :raises InvalidPythonIdentifierError: If the name is not a valid Python identifier. - ''' + """ def __init__( self, name: str, args: list[PythonFunctionArgument], - returns: Union[str, None], - doc: Union[PythonDocstring, None], + returns: str | None, + doc: PythonDocstring | None, decorators: list[str], ) -> None: super().__init__(name, doc, decorators) @@ -150,12 +154,12 @@ class PythonFunctionDefinition(PythonDefinition): @classmethod def from_node(cls, node: ast.stmt) -> PythonFunctionDefinition: - ''' + """ From an AST node. :param node: The AST node. :type node: ast.stmt - ''' + """ return cls( node.name, @@ -165,8 +169,9 @@ class PythonFunctionDefinition(PythonDefinition): [ast.unparse(d) for d in node.decorator_list], ) + class PythonAsyncFunctionDefinition(PythonFunctionDefinition): - ''' + """ A PythonDefinition subclass representing an asynchronous Python function definition. @@ -175,18 +180,19 @@ class PythonAsyncFunctionDefinition(PythonFunctionDefinition): :param args: The arguments. :type args: list[PythonFunctionArgument] :param returns: The return type of the function or class. - :type returns: Union[str, None] + :type returns: str | None :param doc: The docstring. - :type doc: Union[PythonDocstring, None] + :type doc: PythonDocstring | None :param decorators: The definition decorators. :type decorators: list[str] :raises InvalidPythonIdentifierError: If the name is not a valid Python identifier. - ''' + """ + class PythonClassDefinition(PythonDefinition): - ''' + """ A PythonDefinition subclass representing a Python class definition. :param name: The name of the definition. @@ -194,7 +200,7 @@ class PythonClassDefinition(PythonDefinition): :param bases: The base classes. :type bases: list[str] :param doc: The docstring. - :type doc: Union[PythonDocstring, None] + :type doc: PythonDocstring | None :param decorators: The definition decorators. :type decorators: list[str] :param body: @@ -202,13 +208,13 @@ class PythonClassDefinition(PythonDefinition): :raises InvalidPythonIdentifierError: If the name is not a valid Python identifier. - ''' + """ def __init__( self, name: str, bases: list[str], - doc: Union[PythonDocstring, None], + doc: PythonDocstring | None, decorators: list[str], body: list[PythonDefinition], ) -> None: @@ -227,12 +233,12 @@ class PythonClassDefinition(PythonDefinition): @classmethod def from_node(cls, node: ast.stmt) -> PythonClassDefinition: - ''' + """ From an AST node. :param node: The AST node. :type node: ast.stmt - ''' + """ return cls( node.name, @@ -242,16 +248,12 @@ class PythonClassDefinition(PythonDefinition): [ PythonFunctionDefinition.from_node(expr) if isinstance(expr, ast.FunctionDef) - else PythonAsyncFunctionDefinition.from_node(expr) if isinstance(expr, ast.AsyncFunctionDef) - else PythonClassDefinition.from_node(expr) - for expr in node.body if isinstance( - expr, - (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef) + expr, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef) ) ], ) diff --git a/src/jcloud_docsgen/core/python/docstrings.py b/src/jcloud_docsgen/core/python/docstrings.py index 6405eab..441abb8 100644 --- a/src/jcloud_docsgen/core/python/docstrings.py +++ b/src/jcloud_docsgen/core/python/docstrings.py @@ -12,20 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from enum import Enum import docstring_parser -__all__ = [ - 'PythonDocstring' -] +__all__ = ['PythonDocstring'] + class PythonDocstring: - ''' + """ Represents a Python docstring. :param docstring: The docstring as a string. :type docstring: str - ''' + """ def __init__(self, docstring: str) -> None: self.docstring = docstring @@ -39,11 +37,11 @@ class PythonDocstring: return self.docstring == value.docstring def parse(self) -> docstring_parser.Docstring: - ''' + """ Parses the docstring. :return: The parsed docstring. :rtype: docstring_parser.Docstring - ''' + """ return docstring_parser.parse(self.docstring) diff --git a/src/jcloud_docsgen/core/python/namespaces.py b/src/jcloud_docsgen/core/python/namespaces.py index ad3218d..e113583 100644 --- a/src/jcloud_docsgen/core/python/namespaces.py +++ b/src/jcloud_docsgen/core/python/namespaces.py @@ -13,13 +13,15 @@ # limitations under the License. from __future__ import annotations + +from typing import TypeAlias, Union + from ...exceptions import ( InvalidNamespaceError, - NamespaceNotFoundError, NamespaceExistsError, + NamespaceNotFoundError, ) from ...utils import assert_that_is_instance -from typing import Union, TypeAlias, Dict, List __all__ = [ 'PythonNamespace', @@ -27,20 +29,22 @@ __all__ = [ 'PythonModuleNamespace', ] + class PythonNamespace: - ''' + """ The base class for all Python namespaces such as modules or packages. :param name: The name of the namespace. :type name: str - ''' + """ + def __init__(self, name: str) -> None: assert_that_is_instance(name, str) if not name.strip(): raise InvalidNamespaceError( 'invalid namespace', - namespace_identifier = name, + namespace_identifier=name, ) self.name = name @@ -48,7 +52,8 @@ class PythonNamespace: def __repr__(self) -> str: return f'{type(self).__name__}({self.name!r})' -PythonPackageNamespaceDictType: TypeAlias = Dict[ + +PythonPackageNamespaceDictType: TypeAlias = dict[ str, Union[ str, @@ -56,20 +61,21 @@ PythonPackageNamespaceDictType: TypeAlias = Dict[ ], ] + class PythonPackageNamespace(PythonNamespace): - ''' + """ A subclass of ``PythonNamespace`` for Python package namespaces. :param name: The name of the namespace. :type name: str :param sub_namespaces: The sub-namespaces. :type sub_namespaces: list[PythonNamespace] - ''' + """ def __init__( self, name: str, - sub_namespaces: List[PythonNamespace], + sub_namespaces: list[PythonNamespace], ) -> None: assert_that_is_instance(sub_namespaces, list) @@ -77,8 +83,8 @@ class PythonPackageNamespace(PythonNamespace): self._sub_namespaces = sub_namespaces - def namespace(self, sub_namespaces: List[str]) -> PythonNamespace: - ''' + def namespace(self, sub_namespaces: list[str]) -> PythonNamespace: + """ Returns the namespace object with a specific identifier, such as ``['package', 'subpackage', 'module']``. @@ -91,7 +97,7 @@ class PythonPackageNamespace(PythonNamespace): :return: The namespace. :rtype: PythonNamespace - ''' + """ if not sub_namespaces: raise InvalidNamespaceError('invalid namespace') @@ -115,7 +121,7 @@ class PythonPackageNamespace(PythonNamespace): self, package: PythonPackageNamespace, ) -> PythonPackageNamespaceDictType: - ''' + """ Returns the names of all sub-namespaces of the specified package namespace and keeps the package structure. @@ -124,7 +130,7 @@ class PythonPackageNamespace(PythonNamespace): :return: The names if all sub-namespaces. :rtype: PythonPackageNamespaceDictType - ''' + """ return { sn.name: ( @@ -136,13 +142,13 @@ class PythonPackageNamespace(PythonNamespace): } def sub_namespace_names(self) -> PythonPackageNamespaceDictType: - ''' + """ Returns the names of all sub-namespaces and keeps the package structure. :return: The names if all sub-namespaces. :rtype: PythonPackageNamespaceDictType - ''' + """ return self._sub_namespaces_names(self) @@ -159,7 +165,7 @@ class PythonPackageNamespace(PythonNamespace): return type(self).__name__ + repr((self.name, self._sub_namespaces)) def __getitem__(self, name: str) -> PythonNamespace: - ''' + """ Returns a namespace with the specified name. :param name: The name of the namespace @@ -169,7 +175,7 @@ class PythonPackageNamespace(PythonNamespace): :return: The namespace :rtype: PythonNamespace - ''' + """ for sub in self._sub_namespaces: if sub.name == name: @@ -177,11 +183,11 @@ class PythonPackageNamespace(PythonNamespace): raise NamespaceNotFoundError( 'no such namespace', - namespace_identifier = name, + namespace_identifier=name, ) def add(self, namespace: PythonNamespace) -> None: - ''' + """ Adds a namespace. :param namespace: The namespace to add. @@ -190,27 +196,28 @@ class PythonPackageNamespace(PythonNamespace): :raises NamespaceExistsError: If a namespace with the name of the namespace that is attempted to add already exists. - ''' + """ try: self.__getitem__(namespace.name) raise NamespaceExistsError( 'namespace already exists', - namespace_identifier = namespace.name, + namespace_identifier=namespace.name, ) except NamespaceNotFoundError: self._sub_namespaces.append(namespace) @property - def sub_namespaces(self) -> List[PythonNamespace]: + def sub_namespaces(self) -> list[PythonNamespace]: return self._sub_namespaces + class PythonModuleNamespace(PythonNamespace): - ''' + """ A subclass of ``PythonNamespace`` for Python module namespaces. :param name: The name of the namespace. :type name: str - ''' + """ def __init__(self, name: str) -> None: super().__init__(name) diff --git a/src/jcloud_docsgen/exceptions.py b/src/jcloud_docsgen/exceptions.py index ee2b51a..dc81f2e 100644 --- a/src/jcloud_docsgen/exceptions.py +++ b/src/jcloud_docsgen/exceptions.py @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. + class NamespaceError(ValueError): - ''' + """ Base class for namespace errors. - ''' + """ + def __init__(self, *args: object, namespace_identifier: str = '') -> None: super().__init__(*args) self.namespace_identifier = namespace_identifier @@ -25,23 +27,24 @@ class NamespaceError(ValueError): return '' else: return f'{self.args[0]}{ - ": " - if self.namespace_identifier and self.args[0] - else "" - }{ - self.namespace_identifier - if self.args[0] - else "" - }' + ": " if self.namespace_identifier and self.args[0] else "" + }{self.namespace_identifier if self.args[0] else ""}' + class InvalidNamespaceError(NamespaceError): ... + + class NamespaceNotFoundError(NamespaceError): ... + + class NamespaceExistsError(NamespaceError): ... + class PythonIdentifierError(ValueError): - ''' + """ Base class for Python identifier errors. - ''' + """ + def __init__(self, *args: object, identifier: str = '') -> None: super().__init__(*args) self.identifier = identifier @@ -51,21 +54,18 @@ class PythonIdentifierError(ValueError): return '' else: return f'{self.args[0]}{ - ": " - if self.identifier and self.args[0] - else "" - }{ - self.identifier - if self.args[0] - else "" - }' + ": " if self.identifier and self.args[0] else "" + }{self.identifier if self.args[0] else ""}' + class InvalidPythonIdentifierError(PythonIdentifierError): ... + class PythonAnnotationError(ValueError): - ''' + """ Base class for Python annotation errors. - ''' + """ + def __init__(self, *args: object, annotation: str = '') -> None: super().__init__(*args) self.annotation = annotation @@ -75,21 +75,18 @@ class PythonAnnotationError(ValueError): return '' else: return f'{self.args[0]}{ - ": " - if self.annotation and self.args[0] - else "" - }{ - self.annotation - if self.args[0] - else "" - }' + ": " if self.annotation and self.args[0] else "" + }{self.annotation if self.args[0] else ""}' + class InvalidPythonAnnotationError(PythonAnnotationError): ... + class PythonDefinitionError(ValueError): - ''' + """ Base class for Python definition errors. - ''' + """ + def __init__(self, *args: object, definition: str = '') -> None: super().__init__(*args) self.definition = definition @@ -99,13 +96,8 @@ class PythonDefinitionError(ValueError): return '' else: return f'{self.args[0]}{ - ": " - if self.definition and self.args[0] - else "" - }{ - self.definition - if self.args[0] - else "" - }' + ": " if self.definition and self.args[0] else "" + }{self.definition if self.args[0] else ""}' + class PythonArgumentStructureError(PythonDefinitionError): ... diff --git a/src/jcloud_docsgen/utils.py b/src/jcloud_docsgen/utils.py index d602602..197a292 100644 --- a/src/jcloud_docsgen/utils.py +++ b/src/jcloud_docsgen/utils.py @@ -12,30 +12,32 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' +""" The utilities for jcloud_docsgen -''' +""" -import pathlib -import os import errno -from typing import Union +import os +import pathlib import types +from typing import Union try: from warnings import deprecated except ImportError: from typing_extensions import deprecated + @deprecated('Use pathlib.Path instead.') class ExistingDirectory(pathlib.Path): - ''' + """ pathlib.Path subclass that is a directory. ExistingDirectory represents a filesystem path but it also checks whether the path exists and is not a file but a directory. It inherits from pathlib.Path. - ''' + """ + def __init__(self, path, *args, **kwargs) -> None: if not os.path.exists(path): raise FileNotFoundError( @@ -47,15 +49,17 @@ class ExistingDirectory(pathlib.Path): raise NotADirectoryError(errno.ENOTDIR, 'not a directory', path) super().__init__(*(path, *args), **kwargs) + @deprecated('Use pathlib.Path instead.') class ExistingFile(pathlib.Path): - ''' + """ pathlib.Path subclass that is a file. ExistingFile represents a filesystem path but it also checks whether the path exists and is not a directory but a file. It inherits from pathlib.Path. - ''' + """ + def __init__(self, path, *args, **kwargs) -> None: if not os.path.exists(path): raise FileNotFoundError( @@ -67,8 +71,9 @@ class ExistingFile(pathlib.Path): raise IsADirectoryError(errno.EISDIR, 'is a directory', path) super().__init__(*(path, *args), **kwargs) + def _quote(string: str, quotation_mark: str) -> str: - ''' + """ Quotes a string. :param string: The string to quote @@ -78,16 +83,17 @@ def _quote(string: str, quotation_mark: str) -> str: :return: The quoted string :rtype: str - ''' + """ return quotation_mark + string + quotation_mark + def human_readable_list( ls: list, final_separator: str = 'and', quotation_mark: str = '', ) -> str: - ''' + """ Generates a human-readable list from a list. :param ls: The list. @@ -101,7 +107,7 @@ def human_readable_list( :return: The human-readable list. :rtype: str - ''' + """ # empty list if not ls: @@ -111,18 +117,26 @@ def human_readable_list( if len(ls) == 1: return _quote(str(ls[0]), quotation_mark) - return ', '.join( - [ - _quote( - str(obj), - quotation_mark - ) # quote the string representation of the object - for obj in ls[:-1] # do not include the last element of the list - ], - ) + ' ' + final_separator + ' ' + _quote(str(ls[-1]), quotation_mark) + return ( + ', '.join( + [ + _quote( + str(obj), quotation_mark + ) # quote the string representation of the object + for obj in ls[ + :-1 + ] # do not include the last element of the list + ], + ) + + ' ' + + final_separator + + ' ' + + _quote(str(ls[-1]), quotation_mark) + ) + def _list_type_names(types: list[type]) -> list[str]: - ''' + """ Converts a list of types into a list of their names (``__name__`` attribute) @@ -131,22 +145,19 @@ def _list_type_names(types: list[type]) -> list[str]: :return: The list of the names of the types :rtype: list[str] - ''' + """ return [tp.__name__ for tp in types] + def assert_that_is_instance( obj: object, - class_or_tuple: Union[ - type, - types.UnionType, - tuple[type, ...], - ], + class_or_tuple: type | types.UnionType | tuple[type, ...], ) -> None: if not isinstance(class_or_tuple, Union[type, types.UnionType, tuple]): raise TypeError( - f'class_or_tuple: expected \'Union[type, types.UnionType, ' - f'tuple[type, ...]]\', \'got {type(class_or_tuple).__name__}\'', + f"class_or_tuple: expected 'Union[type, types.UnionType, " + f"tuple[type, ...]]', 'got {type(class_or_tuple).__name__}'", ) if not isinstance(obj, class_or_tuple): if isinstance(class_or_tuple, (tuple, types.UnionType)): @@ -157,18 +168,21 @@ def assert_that_is_instance( else: exception_message_expected = '' exception_message_expected += human_readable_list( - _list_type_names(class_or_tuple), 'or', '\'', + _list_type_names(class_or_tuple), + 'or', + "'", ) else: - exception_message_expected = '\'' + class_or_tuple.__name__ + '\'' + exception_message_expected = "'" + class_or_tuple.__name__ + "'" raise TypeError( - f'expected {exception_message_expected}, got \'{type( - obj - ).__name__}\'', + f"expected {exception_message_expected}, got '{ + type(obj).__name__ + }'", ) -def non_empty_str(value: Union[str, None]) -> Union[str, None]: - ''' + +def non_empty_str(value: str | None) -> str | None: + """ Returns the value or ``None``. Returns the value if it is not empty and not `Ǹone``; otherwise, @@ -177,11 +191,11 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]: of spaces, it is also considered empty. :param value: The value. - :type value: Union[str, None] + :type value: str | None :return: The value or ``None``. - :rtype: Union[str, None] - ''' + :rtype: str | None + """ if value is None: return None @@ -191,11 +205,12 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]: return value + def get_relative_path_segments( path: pathlib.Path, root: pathlib.Path, ) -> list[str]: - ''' + """ Returns the path segments relative to ``root``. :param path: The path. @@ -205,7 +220,7 @@ def get_relative_path_segments( :return: The path segments relative to ``root``. :rtype: list[str] - ''' + """ return list( path.resolve() diff --git a/tests/integration/cli/test_cli.py b/tests/integration/cli/test_cli.py index 8e56a32..17a27ec 100644 --- a/tests/integration/cli/test_cli.py +++ b/tests/integration/cli/test_cli.py @@ -15,6 +15,7 @@ import subprocess import sys + def test_cli(): result = subprocess.run( [ @@ -23,12 +24,13 @@ def test_cli(): 'jcloud_docsgen', '--help', ], - capture_output = True, - text = True, + capture_output=True, + text=True, ) stdout = result.stdout.lower() - assert \ - 'usage:' in stdout and \ - 'positional arguments' in stdout and \ - 'options' in stdout and \ - '--help' in stdout + assert ( + 'usage:' in stdout + and 'positional arguments' in stdout + and 'options' in stdout + and '--help' in stdout + ) diff --git a/tests/unit/cli/python_project/project/src/pkg/module.py b/tests/unit/cli/python_project/project/src/pkg/module.py index fd01ebd..3deb2b6 100644 --- a/tests/unit/cli/python_project/project/src/pkg/module.py +++ b/tests/unit/cli/python_project/project/src/pkg/module.py @@ -1,5 +1,5 @@ def f(a: int = 42) -> str: - ''' + """ Does something. :param a: A parameter. @@ -7,5 +7,5 @@ def f(a: int = 42) -> str: :return: A string. :rtype: str - ''' + """ ... diff --git a/tests/unit/cli/test_parser.py b/tests/unit/cli/test_parser.py index 7666e59..c731054 100644 --- a/tests/unit/cli/test_parser.py +++ b/tests/unit/cli/test_parser.py @@ -13,22 +13,31 @@ # limitations under the License. import pytest + from jcloud_docsgen.cli.cli import create_argument_parser -@pytest.mark.parametrize('lang', [ - 'javascript', - 'Python', - 'PYTHON', -]) + +@pytest.mark.parametrize( + 'lang', + [ + 'javascript', + 'Python', + 'PYTHON', + ], +) def test_language_error(lang): parser = create_argument_parser() with pytest.raises(SystemExit): parser.parse_args([lang]) -@pytest.mark.parametrize('lang', [ - 'python', -]) + +@pytest.mark.parametrize( + 'lang', + [ + 'python', + ], +) def test_language_success(lang): parser = create_argument_parser() parser.parse_args([lang]) diff --git a/tests/unit/cli/test_python.py b/tests/unit/cli/test_python.py index 9b11ff0..70891de 100644 --- a/tests/unit/cli/test_python.py +++ b/tests/unit/cli/test_python.py @@ -13,156 +13,176 @@ # limitations under the License. import pathlib + import pytest -from jcloud_docsgen.cli.cli import create_argument_parser, main as cli_main + +from jcloud_docsgen.cli.cli import create_argument_parser +from jcloud_docsgen.cli.cli import main as cli_main from jcloud_docsgen.cli.languages.python import parse_sections_list from jcloud_docsgen.core.python import ( - PythonDefinitionDocumentationIncludeSections + PythonDefinitionDocumentationIncludeSections, ) -@pytest.mark.parametrize('include,exclude,expected', [ - ( - [], - [], - PythonDefinitionDocumentationIncludeSections( - signature = False, - returns = False, - params = False, - exceptions = False, - examples = False, - docstring = False, - bases = False, - decorators = False, - class_body = False, + +@pytest.mark.parametrize( + 'include,exclude,expected', + [ + ( + [], + [], + PythonDefinitionDocumentationIncludeSections( + signature=False, + returns=False, + params=False, + exceptions=False, + examples=False, + docstring=False, + bases=False, + decorators=False, + class_body=False, + ), ), - ), - ( - [], - ['signature'], - PythonDefinitionDocumentationIncludeSections( - signature = False, - returns = False, - params = False, - exceptions = False, - examples = False, - docstring = False, - bases = False, - decorators = False, - class_body = False, + ( + [], + ['signature'], + PythonDefinitionDocumentationIncludeSections( + signature=False, + returns=False, + params=False, + exceptions=False, + examples=False, + docstring=False, + bases=False, + decorators=False, + class_body=False, + ), ), - ), - ( - ['signature'], - ['signature'], - PythonDefinitionDocumentationIncludeSections( - signature = False, - returns = False, - params = False, - exceptions = False, - examples = False, - docstring = False, - bases = False, - decorators = False, - class_body = False, + ( + ['signature'], + ['signature'], + PythonDefinitionDocumentationIncludeSections( + signature=False, + returns=False, + params=False, + exceptions=False, + examples=False, + docstring=False, + bases=False, + decorators=False, + class_body=False, + ), ), - ), - ( - ['signature'], - [], - PythonDefinitionDocumentationIncludeSections( - signature = True, - returns = False, - params = False, - exceptions = False, - examples = False, - docstring = False, - bases = False, - decorators = False, - class_body = False, + ( + ['signature'], + [], + PythonDefinitionDocumentationIncludeSections( + signature=True, + returns=False, + params=False, + exceptions=False, + examples=False, + docstring=False, + bases=False, + decorators=False, + class_body=False, + ), ), - ), - ( - None, - [], - PythonDefinitionDocumentationIncludeSections(), - ), - ( - ['signature', 'exceptions', 'bases', 'class_body'], - ['signature', 'bases'], - PythonDefinitionDocumentationIncludeSections( - signature = False, - returns = False, - params = False, - exceptions = True, - examples = False, - docstring = False, - bases = False, - decorators = False, - class_body = True, + ( + None, + [], + PythonDefinitionDocumentationIncludeSections(), ), - ), - ( - None, - ['params', 'docstring'], - PythonDefinitionDocumentationIncludeSections( - signature = True, - returns = True, - params = False, - exceptions = True, - examples = True, - docstring = False, - bases = True, - decorators = True, - class_body = True, + ( + ['signature', 'exceptions', 'bases', 'class_body'], + ['signature', 'bases'], + PythonDefinitionDocumentationIncludeSections( + signature=False, + returns=False, + params=False, + exceptions=True, + examples=False, + docstring=False, + bases=False, + decorators=False, + class_body=True, + ), ), - ) -]) + ( + None, + ['params', 'docstring'], + PythonDefinitionDocumentationIncludeSections( + signature=True, + returns=True, + params=False, + exceptions=True, + examples=True, + docstring=False, + bases=True, + decorators=True, + class_body=True, + ), + ), + ], +) def test_parse_sections_list(include, exclude, expected): assert parse_sections_list(include, exclude) == expected + def test_sections_error(): parser = create_argument_parser() with pytest.raises(SystemExit): - parser.parse_args([ - 'python', - '-s', - 'param', # correct: `params` - ]) + parser.parse_args( + [ + 'python', + '-s', + 'param', # correct: `params` + ] + ) with pytest.raises(SystemExit): - parser.parse_args([ - 'python', - '-s', - 'params', - 'docstrng', # correct: `docstring` - ]) + parser.parse_args( + [ + 'python', + '-s', + 'params', + 'docstrng', # correct: `docstring` + ] + ) + def test_sections_success(): parser = create_argument_parser() - parser.parse_args([ - 'python', - '-s', - 'params', - ]) - parser.parse_args([ - 'python', - '-s', - 'params', - 'docstring', - ]) + parser.parse_args( + [ + 'python', + '-s', + 'params', + ] + ) + parser.parse_args( + [ + 'python', + '-s', + 'params', + 'docstring', + ] + ) + def test_docs_generation(expectdir): with expectdir('python_project') as output_dir: output_dir: pathlib.Path input_dir = pathlib.Path(__file__).parent / 'python_project/project' - cli_main([ - 'python', - '-s', - 'params', - 'docstring', - '-HTo', - str(output_dir), - str(input_dir), - ]) + cli_main( + [ + 'python', + '-s', + 'params', + 'docstring', + '-HTo', + str(output_dir), + str(input_dir), + ] + ) diff --git a/tests/unit/core/python/_core/test_PythonDefinitionDocumentationGenerator.py b/tests/unit/core/python/_core/test_PythonDefinitionDocumentationGenerator.py index 45d9344..b4ec9b5 100644 --- a/tests/unit/core/python/_core/test_PythonDefinitionDocumentationGenerator.py +++ b/tests/unit/core/python/_core/test_PythonDefinitionDocumentationGenerator.py @@ -12,24 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from src.jcloud_docsgen.core.python._core import ( PythonDefinitionDocumentationGenerator, PythonDefinitionDocumentationIncludeSections, ) +from src.jcloud_docsgen.core.python.arguments import ( + PythonArgumentKind, + PythonFunctionArgument, +) from src.jcloud_docsgen.core.python.definitions import ( - PythonFunctionDefinition, PythonAsyncFunctionDefinition, PythonClassDefinition, -) -from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, - PythonArgumentKind, + PythonFunctionDefinition, ) from src.jcloud_docsgen.core.python.docstrings import PythonDocstring -import pytest + def _signature_section(signature: str) -> str: - ''' + """ The definition documentation signature section of the specified signature. @@ -38,218 +40,224 @@ def _signature_section(signature: str) -> str: :return: The definition documentation signature section. :rtype: str - ''' + """ - return f'''## Function signature + return f"""## Function signature ```python {signature} -```''' +```""" -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - ), - 'a()' - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - 'str', - None, - [], - ), - ), - 'a() -> str' - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - 'str', - None, - [], - ), - ), - 'a(a) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - ], - 'str', - None, - [], - ), - ), - 'a(a: str) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '\'42\'', - None, - ) - ], - 'str', - None, - [], - ), - ), - 'a(a = \'42\') -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '\'42\'', - 'str', - ) - ], - 'str', - None, - [], - ), - ), - 'a(a: str = \'42\') -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - '\'42\'', - 'str', - ) - ], - 'str', - None, - [], - ), - ), - 'a(a: str = \'42\', /) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ) - ], - 'str', - None, - [], - ), - ), - 'a(a, /) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ) - ], - None, - None, - [], - ), - ), - 'a(a, /)', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'definition', - PythonArgumentKind.NORMAL, - None, - 'PythonDefinition', - ), - PythonFunctionArgument( - 'allow_html', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - 'bool', - ), - PythonFunctionArgument( - 'level', - PythonArgumentKind.KEYWORD_ONLY, - '1', - 'int', - ), - ], - 'None', - None, - [], + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), ), + 'a()', ), ( - '__init__(self, definition: PythonDefinition, *, ' - 'allow_html: bool = True, level: int = 1) -> None' + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + 'str', + None, + [], + ), + ), + 'a() -> str', ), - ), -]) + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'str', + None, + [], + ), + ), + 'a(a) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + ], + 'str', + None, + [], + ), + ), + 'a(a: str) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + "'42'", + None, + ) + ], + 'str', + None, + [], + ), + ), + "a(a = '42') -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + "'42'", + 'str', + ) + ], + 'str', + None, + [], + ), + ), + "a(a: str = '42') -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + "'42'", + 'str', + ) + ], + 'str', + None, + [], + ), + ), + "a(a: str = '42', /) -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ) + ], + 'str', + None, + [], + ), + ), + 'a(a, /) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ) + ], + None, + None, + [], + ), + ), + 'a(a, /)', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'definition', + PythonArgumentKind.NORMAL, + None, + 'PythonDefinition', + ), + PythonFunctionArgument( + 'allow_html', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + 'bool', + ), + PythonFunctionArgument( + 'level', + PythonArgumentKind.KEYWORD_ONLY, + '1', + 'int', + ), + ], + 'None', + None, + [], + ), + ), + ( + '__init__(self, definition: PythonDefinition, *, ' + 'allow_html: bool = True, level: int = 1) -> None' + ), + ), + ], +) def test_PythonDefinitionDocumentationGenerator_generate_signature( definition_documentation_generator, expected, ): assert definition_documentation_generator.generate_signature() == expected + @pytest.mark.parametrize( ( 'definition_documentation_generator,exp' @@ -280,205 +288,209 @@ def test_PythonDefinitionDocumentationGenerator_generate_signature_exceptions( definition_documentation_generator.generate_signature() assert str(exc_info.value) == expected_exception_msg -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - ), - 'a()', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - 'str', - None, - [], - ), - ), - 'a() -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - 'str', - None, - [], - ), - ), - 'a(a) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - ], - 'str', - None, - [], - ), - ), - 'a(a: str) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '\'42\'', - None, - ), - ], - 'str', - None, - [], - ), - ), - 'a(a = \'42\') -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '\'42\'', - 'str', - ), - ], - 'str', - None, - [], - ), - ), - 'a(a: str = \'42\') -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - '\'42\'', - 'str', - ), - ], - 'str', - None, - [], - ), - ), - 'a(a: str = \'42\', /) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - 'str', - None, - [], - ), - ), - 'a(a, /) -> str', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - None, - None, - [], - ), - ), - 'a(a, /)', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'definition', - PythonArgumentKind.NORMAL, - None, - 'PythonDefinition', - ), - PythonFunctionArgument( - 'allow_html', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - 'bool', - ), - PythonFunctionArgument( - 'level', - PythonArgumentKind.KEYWORD_ONLY, - '1', - 'int', - ), - ], - 'None', - None, - [], + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), ), + 'a()', ), ( - '__init__(self, definition: PythonDefinition, *, ' - 'allow_html: bool = True, level: int = 1) -> None' + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + 'str', + None, + [], + ), + ), + 'a() -> str', ), - ), -]) + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'str', + None, + [], + ), + ), + 'a(a) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + ], + 'str', + None, + [], + ), + ), + 'a(a: str) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + "'42'", + None, + ), + ], + 'str', + None, + [], + ), + ), + "a(a = '42') -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + "'42'", + 'str', + ), + ], + 'str', + None, + [], + ), + ), + "a(a: str = '42') -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + "'42'", + 'str', + ), + ], + 'str', + None, + [], + ), + ), + "a(a: str = '42', /) -> str", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + 'str', + None, + [], + ), + ), + 'a(a, /) -> str', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + None, + [], + ), + ), + 'a(a, /)', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'definition', + PythonArgumentKind.NORMAL, + None, + 'PythonDefinition', + ), + PythonFunctionArgument( + 'allow_html', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + 'bool', + ), + PythonFunctionArgument( + 'level', + PythonArgumentKind.KEYWORD_ONLY, + '1', + 'int', + ), + ], + 'None', + None, + [], + ), + ), + ( + '__init__(self, definition: PythonDefinition, *, ' + 'allow_html: bool = True, level: int = 1) -> None' + ), + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_signature_section( definition_documentation_generator, expected, @@ -488,253 +500,254 @@ def test_PythonDefinitionDocumentationGenerator__generate_signature_section( == _signature_section(expected) ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - allow_html = False, - skip_empty_sections = True, - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], - ), - allow_html = False, - skip_empty_sections = True, - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a'), - [], - ), - allow_html = False, - skip_empty_sections = True, - ), - '## Docstring\n\na', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a\nb'), - [], - ), - allow_html = False, - skip_empty_sections = True, - ), - '## Docstring\n\na\nb', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + allow_html=False, + skip_empty_sections=True, ), - allow_html = True, - skip_empty_sections = True, - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], - ), - allow_html = True, - skip_empty_sections = True, - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a'), - [], - ), - allow_html = True, - skip_empty_sections = True, + '', ), ( - '

Docstring

a
' - ), - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a\nb'), - [], + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), + allow_html=False, + skip_empty_sections=True, ), - allow_html = True, - skip_empty_sections = True, + '', ), ( - '

Docstring

a\nb
' - ), - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a'), + [], + ), + allow_html=False, + skip_empty_sections=True, ), - allow_html = False, - skip_empty_sections = False, - ), - '## Docstring\n\nThere is no docstring to show.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], - ), - allow_html = False, - skip_empty_sections = False, - ), - '## Docstring\n\nThere is no docstring to show.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a'), - [], - ), - allow_html = False, - skip_empty_sections = False, - ), - '## Docstring\n\na', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a\nb'), - [], - ), - allow_html = False, - skip_empty_sections = False, - ), - '## Docstring\n\na\nb', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - allow_html = True, - skip_empty_sections = False, + '## Docstring\n\na', ), ( - '

Docstring<' - '/h2>

There is no docstring to show.
' - ), - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a\nb'), + [], + ), + allow_html=False, + skip_empty_sections=True, ), - allow_html = True, - skip_empty_sections = False, + '## Docstring\n\na\nb', ), ( - '

Docstring<' - '/h2>

There is no docstring to show.
' - ), - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a'), - [], + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + allow_html=True, + skip_empty_sections=True, ), - allow_html = True, - skip_empty_sections = False, + '', ), ( - '

Docstring

a
' - ), - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a\nb'), - [], + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), + allow_html=True, + skip_empty_sections=True, ), - allow_html = True, - skip_empty_sections = False, + '', ), ( - '

Docstring

a\nb
' + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a'), + [], + ), + allow_html=True, + skip_empty_sections=True, + ), + ( + '

Docstring

a
' + ), ), - ), -]) + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a\nb'), + [], + ), + allow_html=True, + skip_empty_sections=True, + ), + ( + '

Docstring

a\nb
' + ), + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + allow_html=False, + skip_empty_sections=False, + ), + '## Docstring\n\nThere is no docstring to show.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), + allow_html=False, + skip_empty_sections=False, + ), + '## Docstring\n\nThere is no docstring to show.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a'), + [], + ), + allow_html=False, + skip_empty_sections=False, + ), + '## Docstring\n\na', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a\nb'), + [], + ), + allow_html=False, + skip_empty_sections=False, + ), + '## Docstring\n\na\nb', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + allow_html=True, + skip_empty_sections=False, + ), + ( + '

Docstring<' + '/h2>

There is no docstring to show.
' + ), + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), + allow_html=True, + skip_empty_sections=False, + ), + ( + '

Docstring<' + '/h2>

There is no docstring to show.
' + ), + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a'), + [], + ), + allow_html=True, + skip_empty_sections=False, + ), + ( + '

Docstring

a
' + ), + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a\nb'), + [], + ), + allow_html=True, + skip_empty_sections=False, + ), + ( + '

Docstring

a\nb
' + ), + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_docstring_section( definition_documentation_generator, expected, @@ -744,368 +757,366 @@ def test_PythonDefinitionDocumentationGenerator__generate_docstring_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - skip_empty_sections = False, - ), - '## Parameters\n\nThis function takes no parameters.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - None, - None, - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: -- - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - None, - ) - ], - None, - None, - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: `1` - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ) - ], - None, - None, - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: `int` - - Kind: normal - - Default value: -- - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - 'int', - ) - ], - None, - None, - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: `int` - - Kind: normal - - Default value: `1` - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ) - ], - None, - None, - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: -- - - Description: -- - -- Parameter: `b` - - Type: -- - - Kind: positional-only - - Default value: -- - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - None, - PythonDocstring(':param b: a parameter\n:type b: int'), - [], - ), - ), - '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: -- - - Description: -- - -- Parameter: `b` - - Type: `int` - - Kind: positional-only - - Default value: -- - - Description: a parameter''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - None, - PythonDocstring( - ':param b:\n:type b: int', +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], ), - [], ), - ), '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: -- - - Description: -- - -- Parameter: `b` - - Type: `int` - - Kind: positional-only - - Default value: -- - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - None, - PythonDocstring(':param b: \n:type b: int'), - [], - ), - ), '''## Parameters - -- Parameter: `a` - - Type: -- - - Kind: normal - - Default value: -- - - Description: -- - -- Parameter: `b` - - Type: `int` - - Kind: positional-only - - Default value: -- - - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - ], - None, - PythonDocstring(':param b: a parameter\n:type b: int'), - [], - ), - allow_tables = True, + '', ), - '''## Parameters + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + skip_empty_sections=False, + ), + '## Parameters\n\nThis function takes no parameters.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ) + ], + None, + None, + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: -- + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + None, + ) + ], + None, + None, + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: `1` + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ) + ], + None, + None, + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: `int` + + Kind: normal + + Default value: -- + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + 'int', + ) + ], + None, + None, + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: `int` + + Kind: normal + + Default value: `1` + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + None, + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: -- + + Description: -- + +- Parameter: `b` + + Type: -- + + Kind: positional-only + + Default value: -- + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + PythonDocstring(':param b: a parameter\n:type b: int'), + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: -- + + Description: -- + +- Parameter: `b` + + Type: `int` + + Kind: positional-only + + Default value: -- + + Description: a parameter""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + PythonDocstring( + ':param b:\n:type b: int', + ), + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: -- + + Description: -- + +- Parameter: `b` + + Type: `int` + + Kind: positional-only + + Default value: -- + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + PythonDocstring(':param b: \n:type b: int'), + [], + ), + ), + """## Parameters + +- Parameter: `a` + + Type: -- + + Kind: normal + + Default value: -- + + Description: -- + +- Parameter: `b` + + Type: `int` + + Kind: positional-only + + Default value: -- + + Description: --""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + None, + PythonDocstring(':param b: a parameter\n:type b: int'), + [], + ), + allow_tables=True, + ), + """## Parameters | Parameter | Type | Kind | Default value | Description | | --- | --- | --- | --- | --- | | `a` | -- | normal | -- | -- | -| `b` | `int` | positional-only | -- | a parameter |''', - ), -]) +| `b` | `int` | positional-only | -- | a parameter |""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_params_section( definition_documentation_generator, expected, @@ -1115,59 +1126,62 @@ def test_PythonDefinitionDocumentationGenerator__generate_params_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), ), + '', ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + skip_empty_sections=False, ), - skip_empty_sections = False, + '## Exceptions\n\nThis function raises no exceptions.', ), - '## Exceptions\n\nThis function raises no exceptions.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(':raises E: a'), [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(':raises E: a'), + [], + ), ), - ), - '''## Exceptions + """## Exceptions - Exception: `E` - Description: a''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(':raises E:\n:raises E2:'), - [], - ), + Description: a""", ), - '''## Exceptions + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(':raises E:\n:raises E2:'), + [], + ), + ), + """## Exceptions - Exception: `E` @@ -1175,20 +1189,19 @@ def test_PythonDefinitionDocumentationGenerator__generate_params_section( - Exception: `E2` - Description: --''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(':raises E:\n:raises E2: a'), - [], - ), + Description: --""", ), - '''## Exceptions + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(':raises E:\n:raises E2: a'), + [], + ), + ), + """## Exceptions - Exception: `E` @@ -1196,9 +1209,10 @@ def test_PythonDefinitionDocumentationGenerator__generate_params_section( - Exception: `E2` - Description: a''', - ), -]) + Description: a""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_exceptions_section( definition_documentation_generator, expected, @@ -1208,175 +1222,175 @@ def test_PythonDefinitionDocumentationGenerator__generate_exceptions_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------'), - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------\n'), - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------\n\n'), - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), ), - skip_empty_sections = False + '', ), - '## Examples\n\nThere are no examples.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(''), - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), ), - skip_empty_sections = False, + '', ), - '## Examples\n\nThere are no examples.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------'), - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------'), + [], + ), ), - skip_empty_sections = False, + '', ), - '## Examples\n\nThere are no examples.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------\n'), - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------\n'), + [], + ), ), - skip_empty_sections = False, + '', ), - '## Examples\n\nThere are no examples.', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Examples\n--------\n\n'), - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------\n\n'), + [], + ), ), - skip_empty_sections = False, + '', ), - '## Examples\n\nThere are no examples.', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring( - '''Examples + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + skip_empty_sections=False, + ), + '## Examples\n\nThere are no examples.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(''), + [], + ), + skip_empty_sections=False, + ), + '## Examples\n\nThere are no examples.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------'), + [], + ), + skip_empty_sections=False, + ), + '## Examples\n\nThere are no examples.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------\n'), + [], + ), + skip_empty_sections=False, + ), + '## Examples\n\nThere are no examples.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Examples\n--------\n\n'), + [], + ), + skip_empty_sections=False, + ), + '## Examples\n\nThere are no examples.', + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring( + """Examples -------- >>> a() -None''', +None""", + ), + [], ), - [], ), - ), - '''## Examples + """## Examples ```python >>> a() -```''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring( - '''Examples +```""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring( + """Examples -------- >>> a() None >>> a() -None''', +None""", + ), + [], ), - [], ), - ), - '''## Examples + """## Examples ```python >>> a() @@ -1386,28 +1400,27 @@ None''', ```python >>> a() -```''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring( - '''Examples +```""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring( + """Examples -------- >>> a() None >>> b() -1''', +1""", + ), + [], ), - [], ), - ), - '''## Examples + """## Examples ```python >>> a() @@ -1417,9 +1430,10 @@ None ```python >>> b() -```''', - ), -]) +```""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_examples_section( definition_documentation_generator, expected, @@ -1429,105 +1443,104 @@ def test_PythonDefinitionDocumentationGenerator__generate_examples_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - 'int', - None, - [], + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + 'int', + None, + [], + ), ), - ), - '''## Returns + """## Returns -Return type: `int`''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - 'int', - PythonDocstring(':return: value'), - [], - ), - ), - '''## Returns - -value - -Return type: `int`''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - 'int', - PythonDocstring(':return: value\n:rtype: str'), - [], - ), - ), - '''## Returns - -value - -Return type: `int`''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(':return: value\n:rtype: str'), - [], - ), - ), - '''## Returns - -value - -Return type: `str`''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring(':return: value'), - [], - ), - ), - '''## Returns - -value''', - ), - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('a'), - [], - ), - skip_empty_sections = False, +Return type: `int`""", ), ( - '## Returns\n\nThis function does not provi' - 'de any information about its return value.' + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + 'int', + PythonDocstring(':return: value'), + [], + ), + ), + """## Returns + +value + +Return type: `int`""", ), - ), -]) + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + 'int', + PythonDocstring(':return: value\n:rtype: str'), + [], + ), + ), + """## Returns + +value + +Return type: `int`""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(':return: value\n:rtype: str'), + [], + ), + ), + """## Returns + +value + +Return type: `str`""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring(':return: value'), + [], + ), + ), + """## Returns + +value""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('a'), + [], + ), + skip_empty_sections=False, + ), + ( + '## Returns\n\nThis function does not provi' + 'de any information about its return value.' + ), + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_returns_section( definition_documentation_generator, expected, @@ -1537,18 +1550,21 @@ def test_PythonDefinitionDocumentationGenerator__generate_returns_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - ['a', 'b'], + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + ['a', 'b'], + ), ), - ), - '''## Decorators + """## Decorators ```python a @@ -1556,52 +1572,53 @@ a ```python b -```''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - ['a'], - ), +```""", ), - '''## Decorators + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + ['a'], + ), + ), + """## Decorators ```python a -```''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), +```""", ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), ), - skip_empty_sections = False, + '', ), - '''## Decorators + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + skip_empty_sections=False, + ), + """## Decorators -This function or class does not have any decorators.''', - ), -]) +This function or class does not have any decorators.""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_decorators_section( definition_documentation_generator, expected, @@ -1611,97 +1628,101 @@ def test_PythonDefinitionDocumentationGenerator__generate_decorators_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - [], - None, - [], - [], - ), - ), - '', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - [], - None, - [], - [], - ), - skip_empty_sections = False, - ), - '''## Base classes -This class does not have any base classes.''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - ['a'], - None, - [], - [], +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + [], + None, + [], + [], + ), ), - skip_empty_sections = False, + '', ), - '''## Base classes + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + [], + None, + [], + [], + ), + skip_empty_sections=False, + ), + """## Base classes -- `a`''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - ['b'], - None, - [], - [], - ), - skip_empty_sections = False, +This class does not have any base classes.""", ), - '''## Base classes + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + ['a'], + None, + [], + [], + ), + skip_empty_sections=False, + ), + """## Base classes -- `b`''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - ['a', 'b'], - None, - [], - [], - ), - skip_empty_sections = False, +- `a`""", ), - '''## Base classes + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + ['b'], + None, + [], + [], + ), + skip_empty_sections=False, + ), + """## Base classes + +- `b`""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + ['a', 'b'], + None, + [], + [], + ), + skip_empty_sections=False, + ), + """## Base classes - `a` -- `b`''', - ), - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - ['b', 'a'], - None, - [], - [], - ), - skip_empty_sections = False, +- `b`""", ), - '''## Base classes + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + ['b', 'a'], + None, + [], + [], + ), + skip_empty_sections=False, + ), + """## Base classes - `b` -- `a`''', - ), -]) +- `a`""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator__generate_bases_section( definition_documentation_generator, expected, @@ -1711,40 +1732,43 @@ def test_PythonDefinitionDocumentationGenerator__generate_bases_section( == expected ) -@pytest.mark.parametrize('definition_documentation_generator,expected', [ - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. + +@pytest.mark.parametrize( + 'definition_documentation_generator,expected', + [ + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -1757,13 +1781,13 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], + allow_html=False, ), - allow_html = False, - ), - '''# Function `a` + """# Function `a` A function. @@ -1852,43 +1876,41 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. +:rtype: list""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -1901,13 +1923,13 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], ), - ), - ( - '''# Function `a` + ( + """# Function `a` A function. @@ -1981,8 +2003,8 @@ decorate(1, 2, 3) -

Docstring

A ''' - '''function. +

Docstring

A """ + """function. Very long ... @@ -1995,64 +2017,62 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list
''' - ), - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. - -Very long ... - -:param hello: A parameter. -:type hello: str -:param something: Something. -:param value: The value. -:type value: object - -:raises ValueError: If the value is invalid. - -:return: The return value. -:rtype: list''', - ), - ['decorate(1, 2, 3)'], +:rtype: list
""" ), - allow_html = False, - allow_tables = True, ), - '''# Function `a` + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. + +Very long ... + +:param hello: A parameter. +:type hello: str +:param something: Something. +:param value: The value. +:type value: object + +:raises ValueError: If the value is invalid. + +:return: The return value. +:rtype: list""", + ), + ['decorate(1, 2, 3)'], + ), + allow_html=False, + allow_tables=True, + ), + """# Function `a` A function. @@ -2108,43 +2128,41 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. +:rtype: list""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -2157,14 +2175,14 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], + allow_tables=True, ), - allow_tables = True, - ), - ( - '''# Function `a` + ( + """# Function `a` A function. @@ -2205,8 +2223,8 @@ decorate(1, 2, 3) -

Docstring

A ''' - '''function. +

Docstring

A """ + """function. Very long ... @@ -2219,64 +2237,62 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list
''' - ), - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. - -Very long ... - -:param hello: A parameter. -:type hello: str -:param something: Something. -:param value: The value. -:type value: object - -:raises ValueError: If the value is invalid. - -:return: The return value. -:rtype: list''', - ), - ['decorate(1, 2, 3)'], +:rtype: list
""" ), - allow_html = False, - skip_empty_sections = False, ), - '''# Function `a` + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. + +Very long ... + +:param hello: A parameter. +:type hello: str +:param something: Something. +:param value: The value. +:type value: object + +:raises ValueError: If the value is invalid. + +:return: The return value. +:rtype: list""", + ), + ['decorate(1, 2, 3)'], + ), + allow_html=False, + skip_empty_sections=False, + ), + """# Function `a` A function. @@ -2367,43 +2383,41 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. +:rtype: list""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -2416,14 +2430,14 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], + skip_empty_sections=False, ), - skip_empty_sections = False, - ), - ( - '''# Function `a` + ( + """# Function `a` A function. @@ -2499,8 +2513,8 @@ decorate(1, 2, 3) There are no examples. -

Docstring

A ''' - '''function. +

Docstring

A """ + """function. Very long ... @@ -2513,65 +2527,63 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list
''' - ), - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. - -Very long ... - -:param hello: A parameter. -:type hello: str -:param something: Something. -:param value: The value. -:type value: object - -:raises ValueError: If the value is invalid. - -:return: The return value. -:rtype: list''', - ), - ['decorate(1, 2, 3)'], +:rtype: list
""" ), - allow_html = False, - allow_tables = True, - skip_empty_sections = False, ), - '''# Function `a` + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. + +Very long ... + +:param hello: A parameter. +:type hello: str +:param something: Something. +:param value: The value. +:type value: object + +:raises ValueError: If the value is invalid. + +:return: The return value. +:rtype: list""", + ), + ['decorate(1, 2, 3)'], + ), + allow_html=False, + allow_tables=True, + skip_empty_sections=False, + ), + """# Function `a` A function. @@ -2629,43 +2641,41 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. +:rtype: list""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -2678,15 +2688,15 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], + allow_tables=True, + skip_empty_sections=False, ), - allow_tables = True, - skip_empty_sections = False, - ), - ( - '''# Function `a` + ( + """# Function `a` A function. @@ -2729,8 +2739,8 @@ decorate(1, 2, 3) There are no examples. -

Docstring

A ''' - '''function. +

Docstring

A """ + """function. Very long ... @@ -2743,44 +2753,42 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list
''' +:rtype: list
""" + ), ), - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonFunctionDefinition( - 'a', - [ - PythonFunctionArgument( - 'hello', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'world', - PythonArgumentKind.NORMAL, - '1', - None, - ), - PythonFunctionArgument( - 'something', - PythonArgumentKind.KEYWORD_ONLY, - '\'something\'', - 'str', - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - 'bool', - PythonDocstring( - '''A function. + ( + PythonDefinitionDocumentationGenerator( + PythonFunctionDefinition( + 'a', + [ + PythonFunctionArgument( + 'hello', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'world', + PythonArgumentKind.NORMAL, + '1', + None, + ), + PythonFunctionArgument( + 'something', + PythonArgumentKind.KEYWORD_ONLY, + "'something'", + 'str', + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + 'bool', + PythonDocstring( + """A function. Very long ... @@ -2793,126 +2801,124 @@ Very long ... :raises ValueError: If the value is invalid. :return: The return value. -:rtype: list''', +:rtype: list""", + ), + ['decorate(1, 2, 3)'], ), - ['decorate(1, 2, 3)'], + PythonDefinitionDocumentationIncludeSections( + signature=False, + returns=False, + params=False, + exceptions=False, + examples=False, + docstring=False, + bases=False, + decorators=False, + ), + allow_tables=True, + skip_empty_sections=False, ), - PythonDefinitionDocumentationIncludeSections( - signature = False, - returns = False, - params = False, - exceptions = False, - examples = False, - docstring = False, - bases = False, - decorators = False, - ), - allow_tables = True, - skip_empty_sections = False, - ), - '''# Function `a` + """# Function `a` A function. -Very long ...''', - ), - - - ( - PythonDefinitionDocumentationGenerator( - PythonClassDefinition( - 'A', - ['Base1', 'Base2'], - PythonDocstring( - '''A class. +Very long ...""", + ), + ( + PythonDefinitionDocumentationGenerator( + PythonClassDefinition( + 'A', + ['Base1', 'Base2'], + PythonDocstring( + """A class. Examples -------- >>> A() ->>> A()''', +>>> A()""", + ), + ['dec', 'ora', 'tor'], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [], + ), + PythonFunctionDefinition( + 'method', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + 'int', + ), + ], + 'str', + None, + ['decorator'], + ), + PythonAsyncFunctionDefinition( + 'method2', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [], + ), + PythonClassDefinition( + 'B', + ['Base'], + None, + [], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ) + ], + None, + None, + [], + ), + ], + ), + ], + ), + allow_html=False, + allow_tables=True, + include_sections=PythonDefinitionDocumentationIncludeSections( + bases=False, ), - ['dec', 'ora', 'tor'], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - None, - None, - [], - ), - PythonFunctionDefinition( - 'method', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - 'int', - ), - ], - 'str', - None, - ['decorator'], - ), - PythonAsyncFunctionDefinition( - 'method2', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - None, - None, - [], - ), - PythonClassDefinition( - 'B', - ['Base'], - None, - [], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - None, - None, - [], - ), - ], - ), - ], ), - allow_html = False, - allow_tables = True, - include_sections = PythonDefinitionDocumentationIncludeSections( - bases = False, - ), - ), - '''# Class `A` + """# Class `A` A class. @@ -3032,14 +3038,14 @@ Examples -------- >>> A() ->>> A()''', - ), -]) +>>> A()""", + ), + ], +) def test_PythonDefinitionDocumentationGenerator_generate_documentation( definition_documentation_generator, expected, ): assert ( - definition_documentation_generator.generate_documentation() - == expected + definition_documentation_generator.generate_documentation() == expected ) diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator.py index e94a613..c97d66f 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator.py @@ -12,86 +12,92 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pathlib + +import pytest + from src.jcloud_docsgen.core.python import PythonDocumentationGenerator from src.jcloud_docsgen.core.python.namespaces import ( PythonModuleNamespace, PythonPackageNamespace, ) -import pytest -import pathlib -@pytest.mark.parametrize('python_documentation_generator,expected', [ - ( - PythonDocumentationGenerator( - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_1' - ), - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_1/docs' + +@pytest.mark.parametrize( + 'python_documentation_generator,expected', + [ + ( + PythonDocumentationGenerator( + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_1' + ), + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_1/docs' + ), ), + [], ), - [], - ), - ( - PythonDocumentationGenerator( - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_2' - ), - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_2/docs' + ( + PythonDocumentationGenerator( + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_2' + ), + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_2/docs' + ), ), + [ + PythonPackageNamespace( + 'pkg', + [PythonModuleNamespace('module')], + ), + ], ), - [ - PythonPackageNamespace( - 'pkg', - [ - PythonModuleNamespace('module') - ], - ), - ], - ), - ( - PythonDocumentationGenerator( - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_3' - ), - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_3/docs' + ( + PythonDocumentationGenerator( + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_3' + ), + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_3/docs' + ), ), + [ + PythonPackageNamespace( + 'pkg', + [ + PythonModuleNamespace('module'), + PythonPackageNamespace( + 'pkg', + [ + PythonModuleNamespace('module2'), + ], + ), + ], + ), + ], ), - [ - PythonPackageNamespace( - 'pkg', - [ - PythonModuleNamespace('module'), - PythonPackageNamespace( - 'pkg', - [ - PythonModuleNamespace( - 'module2' - ), - ], - ), - ], - ), - ], - ), -]) + ], +) def test_PythonDocumentationGenerator_collect_modules( python_documentation_generator: PythonDocumentationGenerator, expected, ): assert python_documentation_generator.namespace() == expected -@pytest.mark.parametrize('dir', [ - d.name - for d in pathlib.Path( - ( - 'tests/unit/core/python/_core/test_PythonDocume' - 'ntationGenerator/test_generate_documentation/' - ), - ).iterdir() -]) + +@pytest.mark.parametrize( + 'dir', + [ + d.name + for d in pathlib.Path( + ( + 'tests/unit/core/python/_core/test_PythonDocume' + 'ntationGenerator/test_generate_documentation/' + ), + ).iterdir() + ], +) def test_generate_documentation(dir, expectdir): with expectdir( 'test_PythonDocumentationGenerator/test_generate_documentation/' + dir @@ -104,12 +110,12 @@ def test_generate_documentation(dir, expectdir): 'tests/unit/core/python/_core/test_PythonDocume' 'ntationGenerator/test_generate_documentation/' ), - ) / - dir / - 'project', + ) + / dir + / 'project', ), ), pathlib.Path(str(d)), - allow_tables = True, - allow_html = False, - ).generate_documentation() # simplify the tests + allow_tables=True, + allow_html=False, + ).generate_documentation() # simplify the tests diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/exceptions.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/exceptions.py index 6d29928..bce8c8c 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/exceptions.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/exceptions.py @@ -1,8 +1,10 @@ class UserNotFoundError(Exception): """User does not exist.""" + pass class InvalidEmailError(Exception): """Email address is invalid.""" - pass \ No newline at end of file + + pass diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/models.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/models.py index 1f7cc5f..bf4d0c9 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/models.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/models.py @@ -7,7 +7,8 @@ class User: """ Represents a user. """ + id: str name: str email: str - age: Optional[int] = None \ No newline at end of file + age: Optional[int] = None diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/service.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/service.py index 755c0d8..c240ac8 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/service.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/service.py @@ -13,23 +13,16 @@ class UserService: self.storage = storage def create_user( - self, - user_id: str, - name: str, - email: str, - age: int | None = None + self, user_id: str, name: str, email: str, age: int | None = None ) -> User: """ Creates and stores a new user. """ if not is_valid_email(email): - raise InvalidEmailError(f"Invalid email: {email}") + raise InvalidEmailError(f'Invalid email: {email}') user = User( - id=user_id, - name=normalize_name(name), - email=email, - age=age + id=user_id, name=normalize_name(name), email=email, age=age ) self.storage.add(user) @@ -51,4 +44,4 @@ class UserService: try: self.storage.delete(user_id) except KeyError: - raise UserNotFoundError(user_id) \ No newline at end of file + raise UserNotFoundError(user_id) diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/storage.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/storage.py index 29ff61d..659c14f 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/storage.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/storage.py @@ -25,4 +25,4 @@ class InMemoryUserStorage: def list_all(self) -> List[User]: """Returns all users.""" - return list(self._users.values()) \ No newline at end of file + return list(self._users.values()) diff --git a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/utils.py b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/utils.py index 5ca8309..c0b334a 100644 --- a/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/utils.py +++ b/tests/unit/core/python/_core/test_PythonDocumentationGenerator/test_generate_documentation/case03/project/src/user_management/utils.py @@ -5,7 +5,7 @@ def is_valid_email(email: str) -> bool: """ Checks whether an email address is valid. """ - pattern = r"^[\w\.-]+@[\w\.-]+\.\w+$" + pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$' return re.match(pattern, email) is not None @@ -13,4 +13,4 @@ def normalize_name(name: str) -> str: """ Removes extra spaces and formats the name. """ - return " ".join(name.strip().split()).title() \ No newline at end of file + return ' '.join(name.strip().split()).title() diff --git a/tests/unit/core/python/_core/test_PythonModuleDocumentationGenerator.py b/tests/unit/core/python/_core/test_PythonModuleDocumentationGenerator.py index de6ee92..d922136 100644 --- a/tests/unit/core/python/_core/test_PythonModuleDocumentationGenerator.py +++ b/tests/unit/core/python/_core/test_PythonModuleDocumentationGenerator.py @@ -12,10 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pathlib + +import pytest + from src.jcloud_docsgen.core.python import PythonModuleDocumentationGenerator from src.jcloud_docsgen.exceptions import InvalidNamespaceError -import pathlib -import pytest + @pytest.mark.parametrize( 'module_path,src_directory,expected_exception,expected_exception_msg', @@ -216,22 +219,25 @@ def test_PythonModuleDocumentationGenerator_exceptions( PythonModuleDocumentationGenerator(module_path, src_directory) assert str(exc_info.value) == expected_exception_msg -@pytest.mark.parametrize('module_documentation_generator,expected', [ - ( - PythonModuleDocumentationGenerator( - pathlib.Path( - ( - 'tests/unit/core/python/_core/test_pr' - 'oject_dirs/pdir_2/src/pkg/module.py' + +@pytest.mark.parametrize( + 'module_documentation_generator,expected', + [ + ( + PythonModuleDocumentationGenerator( + pathlib.Path( + ( + 'tests/unit/core/python/_core/test_pr' + 'oject_dirs/pdir_2/src/pkg/module.py' + ), ), + pathlib.Path( + 'tests/unit/core/python/_core/test_project_dirs/pdir_2/src/' + ), + allow_tables=True, + allow_html=False, ), - pathlib.Path( - 'tests/unit/core/python/_core/test_project_dirs/pdir_2/src/' - ), - allow_tables = True, - allow_html = False, - ), - '''# Module `pkg.module` + """# Module `pkg.module` A test module. @@ -398,205 +404,21 @@ Barks. ### Docstring -A dog.''' - ), - - ( - PythonModuleDocumentationGenerator( - pathlib.Path( - ( - 'tests/unit/core/python/_core/test_pr' - 'oject_dirs/pdir_2/src/pkg/module.py' - ), - ), - None, - allow_tables = True, - allow_html = False, - ), - '''# Module `module` - -A test module. - -## Function `add` - -Adds two numbers. - - -### Function signature - -```python -add(a: int | float, b: int | float) -> int | float -``` - -### Returns - -The sum. - -Return type: `int | float` - -### Parameters - -| Parameter | Type | Kind | Default value | Description | -| --- | --- | --- | --- | --- | -| `a` | `int | float` | normal | -- | The first number. | -| `b` | `int | float` | normal | -- | The second number. | - - - - - - - -### Docstring - -Adds two numbers. - -:param a: The first number. -:type a: int | float -:param b: The second number. -:type b: int | float - -:return: The sum. -:rtype: int | float - -## Class `Animal` - -A class representing an animal. - - - - -### Body - -#### Constructor (method `__init__`) - -##### Method signature - -```python -__init__(self, name: str) -> None -``` - -##### Returns - -Return type: `None` - -##### Parameters - -| Parameter | Type | Kind | Default value | Description | -| --- | --- | --- | --- | --- | -| `self` | -- | normal | -- | -- | -| `name` | `str` | normal | -- | -- | - -#### Method `greet` - -Returns a greeting. - - -##### Method signature - -```python -greet(self) -``` - -##### Returns - -The greeting. - -Return type: `str` - -##### Parameters - -| Parameter | Type | Kind | Default value | Description | -| --- | --- | --- | --- | --- | -| `self` | -- | normal | -- | -- | - - - - - - - -##### Docstring - -Returns a greeting. - -:return: The greeting. -:rtype: str - - - - - -### Docstring - -A class representing an animal. - -:param name: Its name. -:type name: str - -## Class `Dog` - -A dog. - -### Base classes - -- `Animal` - -### Body - -#### Method `bark` - -Barks. - -##### Method signature - -```python -bark(self) -> None -``` - -##### Returns - -Return type: `None` - -##### Parameters - -| Parameter | Type | Kind | Default value | Description | -| --- | --- | --- | --- | --- | -| `self` | -- | normal | -- | -- | - - - - - - - -##### Docstring - -Barks. - - - - - -### Docstring - -A dog.''' - ), - - ( - PythonModuleDocumentationGenerator( - pathlib.Path( - ( - 'tests/unit/core/python/_core/test_pr' - 'oject_dirs/pdir_2/src/pkg/module.py' - ), - ), - None, - allow_tables = True, - allow_html = True, +A dog.""", ), ( - '''# Module `module` + PythonModuleDocumentationGenerator( + pathlib.Path( + ( + 'tests/unit/core/python/_core/test_pr' + 'oject_dirs/pdir_2/src/pkg/module.py' + ), + ), + None, + allow_tables=True, + allow_html=False, + ), + """# Module `module` A test module. @@ -630,8 +452,190 @@ Return type: `int | float` -

Docstring

Adds ''' - '''two numbers. +### Docstring + +Adds two numbers. + +:param a: The first number. +:type a: int | float +:param b: The second number. +:type b: int | float + +:return: The sum. +:rtype: int | float + +## Class `Animal` + +A class representing an animal. + + + + +### Body + +#### Constructor (method `__init__`) + +##### Method signature + +```python +__init__(self, name: str) -> None +``` + +##### Returns + +Return type: `None` + +##### Parameters + +| Parameter | Type | Kind | Default value | Description | +| --- | --- | --- | --- | --- | +| `self` | -- | normal | -- | -- | +| `name` | `str` | normal | -- | -- | + +#### Method `greet` + +Returns a greeting. + + +##### Method signature + +```python +greet(self) +``` + +##### Returns + +The greeting. + +Return type: `str` + +##### Parameters + +| Parameter | Type | Kind | Default value | Description | +| --- | --- | --- | --- | --- | +| `self` | -- | normal | -- | -- | + + + + + + + +##### Docstring + +Returns a greeting. + +:return: The greeting. +:rtype: str + + + + + +### Docstring + +A class representing an animal. + +:param name: Its name. +:type name: str + +## Class `Dog` + +A dog. + +### Base classes + +- `Animal` + +### Body + +#### Method `bark` + +Barks. + +##### Method signature + +```python +bark(self) -> None +``` + +##### Returns + +Return type: `None` + +##### Parameters + +| Parameter | Type | Kind | Default value | Description | +| --- | --- | --- | --- | --- | +| `self` | -- | normal | -- | -- | + + + + + + + +##### Docstring + +Barks. + + + + + +### Docstring + +A dog.""", + ), + ( + PythonModuleDocumentationGenerator( + pathlib.Path( + ( + 'tests/unit/core/python/_core/test_pr' + 'oject_dirs/pdir_2/src/pkg/module.py' + ), + ), + None, + allow_tables=True, + allow_html=True, + ), + ( + """# Module `module` + +A test module. + +## Function `add` + +Adds two numbers. + + +### Function signature + +```python +add(a: int | float, b: int | float) -> int | float +``` + +### Returns + +The sum. + +Return type: `int | float` + +### Parameters + +| Parameter | Type | Kind | Default value | Description | +| --- | --- | --- | --- | --- | +| `a` | `int | float` | normal | -- | The first number. | +| `b` | `int | float` | normal | -- | The second number. | + + + + + + + +

Docstring

Adds """ + """two numbers. :param a: The first number. :type a: int | float @@ -698,8 +702,8 @@ Return type: `str` -
Docstring
''' - '''Returns a greeting. +
Docstring
""" + """Returns a greeting. :return: The greeting. :rtype: str
@@ -708,8 +712,8 @@ Return type: `str` -

Docstring

A ''' - '''class representing an animal. +

Docstring

A """ + """class representing an animal. :param name: Its name. :type name: str
@@ -750,32 +754,31 @@ Return type: `None` -
Docstring
Barks.''' - '''
+
Docstring
Barks.""" + """
-

Docstring

A dog.''' - '
' - ), - ), - - ( - PythonModuleDocumentationGenerator( - pathlib.Path( - ( - 'tests/unit/core/python/_core/test_pr' - 'oject_dirs/pdir_2/src/pkg/module.py' - ), +

Docstring

A dog.""" + '
' ), - None, - allow_tables = False, - allow_html = True, ), ( - '''# Module `module` + PythonModuleDocumentationGenerator( + pathlib.Path( + ( + 'tests/unit/core/python/_core/test_pr' + 'oject_dirs/pdir_2/src/pkg/module.py' + ), + ), + None, + allow_tables=False, + allow_html=True, + ), + ( + """# Module `module` A test module. @@ -824,8 +827,8 @@ Return type: `int | float` -

Docstring

Adds ''' - '''two numbers. +

Docstring

Adds """ + """two numbers. :param a: The first number. :type a: int | float @@ -913,8 +916,8 @@ Return type: `str` -
Docstring
''' - '''Returns a greeting. +
Docstring
""" + """Returns a greeting. :return: The greeting. :rtype: str
@@ -923,8 +926,8 @@ Return type: `str` -

Docstring

A ''' - '''class representing an animal. +

Docstring

A """ + """class representing an animal. :param name: Its name. :type name: str
@@ -971,31 +974,30 @@ Return type: `None` -
Docstring
Barks.''' - '''
+
Docstring
Barks.""" + """
-

Docstring

A ''' - 'dog.
' - ), - ), - - ( - PythonModuleDocumentationGenerator( - pathlib.Path( - ( - 'tests/unit/core/python/_core/test_pr' - 'oject_dirs/pdir_2/src/pkg/module.py' - ), +

Docstring

A """ + 'dog.
' ), - None, - allow_tables = False, - allow_html = False, ), - '''# Module `module` + ( + PythonModuleDocumentationGenerator( + pathlib.Path( + ( + 'tests/unit/core/python/_core/test_pr' + 'oject_dirs/pdir_2/src/pkg/module.py' + ), + ), + None, + allow_tables=False, + allow_html=False, + ), + """# Module `module` A test module. @@ -1204,9 +1206,10 @@ Barks. ### Docstring -A dog.''' - ), -]) +A dog.""", + ), + ], +) def test_PythonModuleDocumentationGenerator_exceptions( module_documentation_generator, expected, diff --git a/tests/unit/core/python/_core/test__argument_kind_human_readable.py b/tests/unit/core/python/_core/test__argument_kind_human_readable.py index 9100105..b68ed7e 100644 --- a/tests/unit/core/python/_core/test__argument_kind_human_readable.py +++ b/tests/unit/core/python/_core/test__argument_kind_human_readable.py @@ -12,16 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python._core import _argument_kind_human_readable -from src.jcloud_docsgen.core.python.arguments import PythonArgumentKind import pytest -@pytest.mark.parametrize('argument_kind,expected', [ - (PythonArgumentKind.NORMAL, 'normal'), - (PythonArgumentKind.POSITIONAL_ONLY, 'positional-only'), - (PythonArgumentKind.KEYWORD_ONLY, 'keyword-only'), - (PythonArgumentKind.VARARG, 'vararg'), - (PythonArgumentKind.KWARGS, 'kwargs'), -]) +from src.jcloud_docsgen.core.python._core import _argument_kind_human_readable +from src.jcloud_docsgen.core.python.arguments import PythonArgumentKind + + +@pytest.mark.parametrize( + 'argument_kind,expected', + [ + (PythonArgumentKind.NORMAL, 'normal'), + (PythonArgumentKind.POSITIONAL_ONLY, 'positional-only'), + (PythonArgumentKind.KEYWORD_ONLY, 'keyword-only'), + (PythonArgumentKind.VARARG, 'vararg'), + (PythonArgumentKind.KWARGS, 'kwargs'), + ], +) def test__argument_kind_human_readable(argument_kind, expected): assert _argument_kind_human_readable(argument_kind) == expected diff --git a/tests/unit/core/python/_core/test__collect_definitions.py b/tests/unit/core/python/_core/test__collect_definitions.py index 56e3b6e..fdb4cc3 100644 --- a/tests/unit/core/python/_core/test__collect_definitions.py +++ b/tests/unit/core/python/_core/test__collect_definitions.py @@ -12,21 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ast + +import pytest + from src.jcloud_docsgen.core.python._core import _collect_definitions +from src.jcloud_docsgen.core.python.arguments import ( + PythonArgumentKind, + PythonFunctionArgument, +) from src.jcloud_docsgen.core.python.definitions import ( PythonClassDefinition, PythonFunctionDefinition, ) -from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, - PythonArgumentKind, -) from src.jcloud_docsgen.core.python.docstrings import PythonDocstring -import pytest -import ast + def module(source_code: str) -> ast.Module: - ''' + """ Returns an AST module of the source code. :param source_code: The module source code. @@ -34,38 +37,41 @@ def module(source_code: str) -> ast.Module: :return: The AST module. :rtype: ast.Module - ''' + """ return ast.parse(source_code) -@pytest.mark.parametrize('module,expected', [ - ( - module('def add(a, b):\n\treturn a + b'), - [ - PythonFunctionDefinition( - 'add', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - None, - None, - [], - ), - ], - ), - ( - module('''def add(a: int | float, b: int | float) -> int | float: + +@pytest.mark.parametrize( + 'module,expected', + [ + ( + module('def add(a, b):\n\treturn a + b'), + [ + PythonFunctionDefinition( + 'add', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [], + ), + ], + ), + ( + module('''def add(a: int | float, b: int | float) -> int | float: """Adds two numbers.""" return a + b @@ -89,87 +95,87 @@ class Something: """ return self._value '''), - [ - PythonFunctionDefinition( - 'add', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int | float', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int | float', - ), - ], - 'int | float', - PythonDocstring('Adds two numbers.'), - [], - ), - PythonClassDefinition( - 'Something', - [], - PythonDocstring('A class.'), - [], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.NORMAL, - '42', - 'typing.Any', - ), - ], - 'None', - None, - [], - ), - PythonFunctionDefinition( - 'value', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - 'typing.Any', - PythonDocstring('The value.'), - ['property'], - ), - PythonFunctionDefinition( - 'get_value', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - 'typing.Any', - PythonDocstring('Returns the value.'), - [], - ), - ], - ), - ], - ), - ( - module('''from src.jcloud_docsgen.core.python import ( + [ + PythonFunctionDefinition( + 'add', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int | float', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int | float', + ), + ], + 'int | float', + PythonDocstring('Adds two numbers.'), + [], + ), + PythonClassDefinition( + 'Something', + [], + PythonDocstring('A class.'), + [], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.NORMAL, + '42', + 'typing.Any', + ), + ], + 'None', + None, + [], + ), + PythonFunctionDefinition( + 'value', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'typing.Any', + PythonDocstring('The value.'), + ['property'], + ), + PythonFunctionDefinition( + 'get_value', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'typing.Any', + PythonDocstring('Returns the value.'), + [], + ), + ], + ), + ], + ), + ( + module("""from src.jcloud_docsgen.core.python import ( PythonDocumentationGenerator ) from src.jcloud_docsgen.core.python.namespaces import ( @@ -235,139 +241,142 @@ def test_PythonDocumentationGenerator_collect_modules( python_documentation_generator: PythonDocumentationGenerator, expected ): - assert python_documentation_generator.namespace() == expected'''), - [ - PythonFunctionDefinition( - 'test_PythonDocumentationGenerator_type_exceptions', - [ - PythonFunctionArgument( - 'project_directory', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'docs_directory', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - None, - None, - [ - ( - '''pytest.mark.parametrize('project_directo''' - '''ry,docs_directory', [(1, 1), (1, None), ''' - '''(42, None), (pathlib.Path('tests'), 1), ''' - '''(pathlib.Path('tests/'), 1), (1, pathlib''' - '''.Path('tests/')), (1, pathlib.Path('test''' - '''s')), (None, pathlib.Path('tests'))])''' - ), - ], - ), - PythonFunctionDefinition( - 'test_PythonDocumentationGenerator_collect_modules', - [ - PythonFunctionArgument( - 'python_documentation_generator', - PythonArgumentKind.NORMAL, - None, - 'PythonDocumentationGenerator', - ), - PythonFunctionArgument( - 'expected', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - None, - None, - [( - '''pytest.mark.parametrize('python_documentation_gener''' - '''ator,expected', [(PythonDocumentationGenerator(path''' - '''lib.Path('tests/unit/core/python/_core/test_project''' - '''_dirs/pdir_1'), pathlib.Path('tests/unit/core/pytho''' - '''n/_core/test_project_dirs/pdir_1/docs')), []), (Pyt''' - '''honDocumentationGenerator(pathlib.Path('tests/unit/''' - '''core/python/_core/test_project_dirs/pdir_2'), pathl''' - '''ib.Path('tests/unit/core/python/_core/test_project_''' - '''dirs/pdir_2/docs')), [PythonPackageNamespace('pkg',''' - ''' [PythonModuleNamespace('module')])]), (PythonDocum''' - '''entationGenerator(pathlib.Path('tests/unit/core/pyt''' - '''hon/_core/test_project_dirs/pdir_3'), pathlib.Path(''' - ''''tests/unit/core/python/_core/test_project_dirs/pdi''' - '''r_3/docs')), [PythonPackageNamespace('pkg', [Python''' - '''ModuleNamespace(\'module'), PythonPackageNamespace(''' - '''\'pkg\', [PythonModuleNamespace(\'module2')])])])])''' - )], - ), - ], - ), - ( - module( - '''class C1: + assert python_documentation_generator.namespace() == expected"""), + [ + PythonFunctionDefinition( + 'test_PythonDocumentationGenerator_type_exceptions', + [ + PythonFunctionArgument( + 'project_directory', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'docs_directory', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [ + ( + """pytest.mark.parametrize('project_directo""" + """ry,docs_directory', [(1, 1), (1, None), """ + """(42, None), (pathlib.Path('tests'), 1), """ + """(pathlib.Path('tests/'), 1), (1, pathlib""" + """.Path('tests/')), (1, pathlib.Path('test""" + """s')), (None, pathlib.Path('tests'))])""" + ), + ], + ), + PythonFunctionDefinition( + 'test_PythonDocumentationGenerator_collect_modules', + [ + PythonFunctionArgument( + 'python_documentation_generator', + PythonArgumentKind.NORMAL, + None, + 'PythonDocumentationGenerator', + ), + PythonFunctionArgument( + 'expected', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [ + ( + """pytest.mark.parametrize('python_documentation_gener""" + """ator,expected', [(PythonDocumentationGenerator(path""" + """lib.Path('tests/unit/core/python/_core/test_project""" + """_dirs/pdir_1'), pathlib.Path('tests/unit/core/pytho""" + """n/_core/test_project_dirs/pdir_1/docs')), []), (Pyt""" + """honDocumentationGenerator(pathlib.Path('tests/unit/""" + """core/python/_core/test_project_dirs/pdir_2'), pathl""" + """ib.Path('tests/unit/core/python/_core/test_project_""" + """dirs/pdir_2/docs')), [PythonPackageNamespace('pkg',""" + """ [PythonModuleNamespace('module')])]), (PythonDocum""" + """entationGenerator(pathlib.Path('tests/unit/core/pyt""" + """hon/_core/test_project_dirs/pdir_3'), pathlib.Path(""" + """'tests/unit/core/python/_core/test_project_dirs/pdi""" + """r_3/docs')), [PythonPackageNamespace('pkg', [Python""" + """ModuleNamespace(\'module'), PythonPackageNamespace(""" + """\'pkg\', [PythonModuleNamespace(\'module2')])])])])""" + ) + ], + ), + ], + ), + ( + module( + """class C1: class C2: class C3: def function(self, value: bool, /, arg) -> bool: def should_be_not_in_the_result(arg: int) -> object: pass - return not value''' - ), - [ - PythonClassDefinition( - 'C1', - [], - None, - [], - [ - PythonClassDefinition( - 'C2', - [], - None, - [], - [ - PythonClassDefinition( - 'C3', - [], - None, - [], - [ - PythonFunctionDefinition( - 'function', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'bool', - ), - PythonFunctionArgument( - 'arg', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - 'bool', - None, - [], - ), - ], - ), - ], - ), - ], + return not value""" ), - ], - ), -]) + [ + PythonClassDefinition( + 'C1', + [], + None, + [], + [ + PythonClassDefinition( + 'C2', + [], + None, + [], + [ + PythonClassDefinition( + 'C3', + [], + None, + [], + [ + PythonFunctionDefinition( + 'function', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'bool', + ), + PythonFunctionArgument( + 'arg', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'bool', + None, + [], + ), + ], + ), + ], + ), + ], + ), + ], + ), + ], +) def test___collect_definitions(module, expected): assert list(_collect_definitions(module)) == expected diff --git a/tests/unit/core/python/_core/test__fit_row_length.py b/tests/unit/core/python/_core/test__fit_row_length.py index 9981799..7fc904e 100644 --- a/tests/unit/core/python/_core/test__fit_row_length.py +++ b/tests/unit/core/python/_core/test__fit_row_length.py @@ -12,44 +12,54 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python._core import _fit_row_length import pytest -@pytest.mark.parametrize('expected_length,row,expected', [ - (0, (), ()), - (1, (), (None,)), - (2, (), (None, None)), - (2, (1,), (1, None)), +from src.jcloud_docsgen.core.python._core import _fit_row_length - (0, (1,), ()), - (1, (1, 2), (1,)), - (1, (1, 2), (1,)), - (0, (1, 2), ()), - (0, (1, 2, 3), ()), - (1, (1, 2, 3), (1,)), - (2, (1, 2, 3), (1, 2)), - (1, (1,), (1,)), - (2, (1, 1), (1, 1)), - (2, (1, 2), (1, 2)), - (3, (1, 2, 3), (1, 2, 3)), -]) +@pytest.mark.parametrize( + 'expected_length,row,expected', + [ + (0, (), ()), + (1, (), (None,)), + (2, (), (None, None)), + (2, (1,), (1, None)), + (0, (1,), ()), + (1, (1, 2), (1,)), + (1, (1, 2), (1,)), + (0, (1, 2), ()), + (0, (1, 2, 3), ()), + (1, (1, 2, 3), (1,)), + (2, (1, 2, 3), (1, 2)), + (1, (1,), (1,)), + (2, (1, 1), (1, 1)), + (2, (1, 2), (1, 2)), + (3, (1, 2, 3), (1, 2, 3)), + ], +) def test__fit_row_length(expected_length, row, expected): assert _fit_row_length(expected_length, row) == expected -@pytest.mark.parametrize('row', [ - (), - (1,), - (1, 2), - (1, 2, 3), - (1, 2, 3, 456), -]) -@pytest.mark.parametrize('expected_length,expected_exception', [ - (-1, ValueError), - (-2, ValueError), - (-3, ValueError), - (-42, ValueError), -]) + +@pytest.mark.parametrize( + 'row', + [ + (), + (1,), + (1, 2), + (1, 2, 3), + (1, 2, 3, 456), + ], +) +@pytest.mark.parametrize( + 'expected_length,expected_exception', + [ + (-1, ValueError), + (-2, ValueError), + (-3, ValueError), + (-42, ValueError), + ], +) def test__fit_row_length_exceptions(expected_length, row, expected_exception): with pytest.raises(expected_exception) as exc_info: _fit_row_length(expected_length, row) diff --git a/tests/unit/core/python/_core/test__function_params_info.py b/tests/unit/core/python/_core/test__function_params_info.py index 014b4cd..ccb1064 100644 --- a/tests/unit/core/python/_core/test__function_params_info.py +++ b/tests/unit/core/python/_core/test__function_params_info.py @@ -12,21 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +import docstring_parser +import pytest + from src.jcloud_docsgen.core.python._core import ( _function_params_info, _FunctionParamInfo, ) from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, PythonArgumentKind, + PythonFunctionArgument, ) -import pytest -import docstring_parser + def docstring_args_list( docstring: str, ) -> list[docstring_parser.DocstringParam]: - ''' + """ Returns the parameter list of a docstring. :param docstring: The docstring @@ -34,82 +36,164 @@ def docstring_args_list( :return: The parameter list. :rtype: list[docstring_parser.DocstringParam] - ''' + """ return docstring_parser.parse(docstring).params -@pytest.mark.parametrize('arg_list,docstring,expected', [ - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'int'), - ], ':param a: a\n:type a: str', { - 'a': _FunctionParamInfo('int', 'a'), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - ], ':param a: a\n:type a: str', { - 'a': _FunctionParamInfo('str', 'a'), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', None), - ], ':param a: a\n:type a: str', { - 'a': _FunctionParamInfo('str', 'a'), - 'b': _FunctionParamInfo(None, None), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', 'int'), - ], ':param a: a\n:type a: str', { - 'a': _FunctionParamInfo('str', 'a'), - 'b': _FunctionParamInfo('int', None), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - PythonFunctionArgument('b', PythonArgumentKind.NORMAL, '', 'int'), - ], ':param a: a\n:type a: str\n:param b: b\n:type b: str', { - 'a': _FunctionParamInfo('str', 'a'), - 'b': _FunctionParamInfo('int', 'b'), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - ], ':param a: a\n:type a: str\n:param b: b\n:type b: int', { - 'a': _FunctionParamInfo('str', 'a'), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - ], '', { - 'a': _FunctionParamInfo(None, None), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'), - ], '', { - 'a': _FunctionParamInfo('str', None), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'), - ], ':param a:\n:type a: int', { - 'a': _FunctionParamInfo('str', ''), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - ], ':param a:\n:type a: int', { - 'a': _FunctionParamInfo('int', ''), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', None), - ], ':param a: a', { - 'a': _FunctionParamInfo(None, 'a'), - }), - ([ - PythonFunctionArgument('a', PythonArgumentKind.NORMAL, '', 'str'), - ], ':param a: a', { - 'a': _FunctionParamInfo('str', 'a'), - }), - ([], ':param a: a\n:type a: str', {}), - ([], '', {}), -]) + +@pytest.mark.parametrize( + 'arg_list,docstring,expected', + [ + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', 'int' + ), + ], + ':param a: a\n:type a: str', + { + 'a': _FunctionParamInfo('int', 'a'), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + ], + ':param a: a\n:type a: str', + { + 'a': _FunctionParamInfo('str', 'a'), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + PythonFunctionArgument( + 'b', PythonArgumentKind.NORMAL, '', None + ), + ], + ':param a: a\n:type a: str', + { + 'a': _FunctionParamInfo('str', 'a'), + 'b': _FunctionParamInfo(None, None), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + PythonFunctionArgument( + 'b', PythonArgumentKind.NORMAL, '', 'int' + ), + ], + ':param a: a\n:type a: str', + { + 'a': _FunctionParamInfo('str', 'a'), + 'b': _FunctionParamInfo('int', None), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + PythonFunctionArgument( + 'b', PythonArgumentKind.NORMAL, '', 'int' + ), + ], + ':param a: a\n:type a: str\n:param b: b\n:type b: str', + { + 'a': _FunctionParamInfo('str', 'a'), + 'b': _FunctionParamInfo('int', 'b'), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + ], + ':param a: a\n:type a: str\n:param b: b\n:type b: int', + { + 'a': _FunctionParamInfo('str', 'a'), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + ], + '', + { + 'a': _FunctionParamInfo(None, None), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', 'str' + ), + ], + '', + { + 'a': _FunctionParamInfo('str', None), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', 'str' + ), + ], + ':param a:\n:type a: int', + { + 'a': _FunctionParamInfo('str', ''), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + ], + ':param a:\n:type a: int', + { + 'a': _FunctionParamInfo('int', ''), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', None + ), + ], + ':param a: a', + { + 'a': _FunctionParamInfo(None, 'a'), + }, + ), + ( + [ + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, '', 'str' + ), + ], + ':param a: a', + { + 'a': _FunctionParamInfo('str', 'a'), + }, + ), + ([], ':param a: a\n:type a: str', {}), + ([], '', {}), + ], +) def test__function_params_types(arg_list, docstring, expected): - assert _function_params_info( - arg_list, - docstring_args_list(docstring) - ) == expected + assert ( + _function_params_info(arg_list, docstring_args_list(docstring)) + == expected + ) diff --git a/tests/unit/core/python/_core/test__markdown_table.py b/tests/unit/core/python/_core/test__markdown_table.py index 90b49b4..ec0081a 100644 --- a/tests/unit/core/python/_core/test__markdown_table.py +++ b/tests/unit/core/python/_core/test__markdown_table.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python._core import _markdown_table import pytest +from src.jcloud_docsgen.core.python._core import _markdown_table + + @pytest.mark.parametrize( ( 'header,body,allow_markdown_table,force_row_le' @@ -55,9 +57,9 @@ import pytest False, True, '--', - '''| a | + """| a | | --- | -| 1 |''', +| 1 |""", ), ( ['a'], @@ -66,9 +68,9 @@ import pytest False, True, '--', - '''| a | + """| a | | --- | -| 1 |''', +| 1 |""", ), ( ['a', 'b'], @@ -77,9 +79,9 @@ import pytest False, True, '--', - '''| a | b | + """| a | b | | --- | --- | -| 1 | 2 |''', +| 1 | 2 |""", ), ( ['a', 'b'], @@ -88,9 +90,9 @@ import pytest False, True, '--', - '''| a | b | + """| a | b | | --- | --- | -| 1 | -- |''', +| 1 | -- |""", ), ( ['a', 'b'], @@ -99,9 +101,9 @@ import pytest False, True, '--', - '''| a | b | + """| a | b | | --- | --- | -| -- | -- |''', +| -- | -- |""", ), ( ['a', 'b'], @@ -110,10 +112,10 @@ import pytest False, True, '--', - '''| a | b | + """| a | b | | --- | --- | | 1 | 2 | -| 3 | 4 |''', +| 3 | 4 |""", ), ( ['a'], @@ -122,9 +124,9 @@ import pytest False, True, '--', - '''| a | + """| a | | --- | -| line1 line2 |''', +| line1 line2 |""", ), ( ['a'], @@ -133,11 +135,10 @@ import pytest False, False, '--', - '''| a | + """| a | | --- | -| line1\nline2 |''', +| line1\nline2 |""", ), - ( [], [], @@ -190,9 +191,9 @@ import pytest False, True, '--', - '''- a: 1 + """- a: 1 - b: 2''', + b: 2""", ), ( ['a', 'b'], @@ -201,9 +202,9 @@ import pytest False, True, '--', - '''- a: 1 + """- a: 1 - b: --''', + b: --""", ), ( ['a', 'b'], @@ -212,9 +213,9 @@ import pytest False, True, '--', - '''- a: -- + """- a: -- - b: --''', + b: --""", ), ( ['a', 'b'], @@ -223,13 +224,13 @@ import pytest False, True, '--', - '''- a: 1 + """- a: 1 b: 2 - a: 3 - b: 4''', + b: 4""", ), ( ['a'], @@ -260,14 +261,18 @@ def test__markdown_table( missing_value, expected, ): - assert _markdown_table( - header, - body, - allow_markdown_table = allow_markdown_table, - force_row_lengths = force_row_lengths, - one_line_values = one_line_values, - missing_value = missing_value, - ) == expected + assert ( + _markdown_table( + header, + body, + allow_markdown_table=allow_markdown_table, + force_row_lengths=force_row_lengths, + one_line_values=one_line_values, + missing_value=missing_value, + ) + == expected + ) + @pytest.mark.parametrize( ( @@ -335,7 +340,6 @@ def test__markdown_table( ValueError, 'expected 2 values, got 3', ), - ( ['a'], [(1, 2)], @@ -412,9 +416,9 @@ def test__markdown_table_exceptions( _markdown_table( header, body, - allow_markdown_table = allow_markdown_table, - force_row_lengths = force_row_lengths, - one_line_values = one_line_values, - missing_value = missing_value, + allow_markdown_table=allow_markdown_table, + force_row_lengths=force_row_lengths, + one_line_values=one_line_values, + missing_value=missing_value, ) assert str(exc_info.value) == expected_exception_msg diff --git a/tests/unit/core/python/_core/test__signature_argument_list.py b/tests/unit/core/python/_core/test__signature_argument_list.py index b586e4b..b381864 100644 --- a/tests/unit/core/python/_core/test__signature_argument_list.py +++ b/tests/unit/core/python/_core/test__signature_argument_list.py @@ -12,273 +12,336 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python._core import _signature_argument_list -from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, - PythonArgumentKind, -) import pytest -@pytest.mark.parametrize('argument_list,expected', [ - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, +from src.jcloud_docsgen.core.python._core import _signature_argument_list +from src.jcloud_docsgen.core.python.arguments import ( + PythonArgumentKind, + PythonFunctionArgument, +) + + +@pytest.mark.parametrize( + 'argument_list,expected', + [ + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + ['a'], ), - ], ['a']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + ], + ['a', '/'], ), - ], ['a', '/']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + ['a', '/', 'b'], ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ['a', '/', 'b', '*', 'c'], ), - ], ['a', '/', 'b']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ['b', '*', 'c'], ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, + ( + [ + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ['*', 'c'], ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ['b', '/', '*', 'c'], ), - ], ['a', '/', 'b', '*', 'c']), - ([ - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, + ( + [ + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ) + ], + ['*args'], ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ['a', '*args'], ), - ], ['b', '*', 'c']), - ([ - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ['a', '/', '*args'], ), - ], ['*', 'c']), - ([ - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ['*args', 'a'], ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['*args', '**kwargs'], ), - ], ['b', '/', '*', 'c']), - ([ - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ) - ], ['*args']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['a', '/', '*args', '**kwargs'], ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['a', '*args', '**kwargs'], ), - ], ['a', '*args']), - ([ - PythonFunctionArgument( - 'a', PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['*args', 'a', '**kwargs'], ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['*', 'a', '**kwargs'], ), - ], ['a', '/', '*args']), - ([ - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['a', '**kwargs'], ), - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ['a', '/', '**kwargs'], ), - ], ['*args', 'a']), - ([ - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, + ( + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + 'int', + ), + ], + ['a: int = 1'], ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['*args', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['a', '/', '*args', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['a', '*args', '**kwargs']), - ([ - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['*args', 'a', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['*', 'a', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['a', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], ['a', '/', '**kwargs']), - ([ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - 'int', - ), - ], ['a: int = 1']), -]) + ], +) def test__signature_argument_list(argument_list, expected): assert _signature_argument_list(argument_list) == expected diff --git a/tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py b/tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py index b44f01e..7da0ee4 100644 --- a/tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py +++ b/tests/unit/core/python/_core/test_project_dirs/pdir_2/src/pkg/module.py @@ -1,9 +1,10 @@ -''' +""" A test module. -''' +""" + def add(a: int | float, b: int | float) -> int | float: - ''' + """ Adds two numbers. :param a: The first number. @@ -13,38 +14,41 @@ def add(a: int | float, b: int | float) -> int | float: :return: The sum. :rtype: int | float - ''' + """ return a + b + class Animal: - ''' + """ A class representing an animal. :param name: Its name. :type name: str - ''' + """ + def __init__(self, name: str) -> None: self.name = name def greet(self): - ''' + """ Returns a greeting. :return: The greeting. :rtype: str - ''' + """ return f'Hi there! My name is {self.name}' + class Dog(Animal): - ''' + """ A dog. - ''' + """ def bark(self) -> None: - ''' + """ Barks. - ''' + """ print('Woof!') diff --git a/tests/unit/core/python/arguments/test_PythonASTArgumentsListParser.py b/tests/unit/core/python/arguments/test_PythonASTArgumentsListParser.py index 2b1a8b8..7af0d65 100644 --- a/tests/unit/core/python/arguments/test_PythonASTArgumentsListParser.py +++ b/tests/unit/core/python/arguments/test_PythonASTArgumentsListParser.py @@ -12,16 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.arguments import ( - PythonASTArgumentsListParser, - PythonFunctionArgument, - PythonArgumentKind, -) -import pytest import ast +import pytest + +from src.jcloud_docsgen.core.python.arguments import ( + PythonArgumentKind, + PythonASTArgumentsListParser, + PythonFunctionArgument, +) + + def argument_list(argument_list: str) -> ast.arguments: - ''' + """ Returns an AST argument list from the argument list source code :param argument_list: The argument list. @@ -29,916 +32,922 @@ def argument_list(argument_list: str) -> ast.arguments: :return: The AST argument list. :rtype: ast.arguments - ''' + """ return ast.parse('def func(' + argument_list + '): ...').body[0].args -@pytest.mark.parametrize('ast_arguments_list,expected', [ - ( - argument_list('a'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - ), - ( - argument_list('a: str'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - ], - ), - ( - argument_list('a: str | int'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str | int', - ), - ], - ), - ( - argument_list('a: str, b'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - ), - ( - argument_list('a: str, b: int'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - ], - ), - ( - argument_list('a, b: int'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - ], - ), - ( - argument_list('a, b, *args'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - ], - ), - ( - argument_list('a: int, b, *args'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - ], - ), - ( - argument_list('a, b: str, *args'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - ], - ), - ( - argument_list('a: int, b: str, *args'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - ], - ), - ( - argument_list('a: int, b: str, *args: float'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'str', - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - 'float', - ), - ], - ), - ( - argument_list('a: int, b, *args: float'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - 'float', - ), - ], - ), - ( - argument_list('a: int, *args: float'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - 'float', - ), - ], - ), - ( - argument_list('a: int, /, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a: int, **kwargs: str'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - 'str', - ), - ], - ), - ( - argument_list('a: int, /, b, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a: int, /, b'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - ), - ( - argument_list('a: int, /, b, *, c'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - ], - ), - ( - argument_list('a, b, *, c'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - ], - ), - ( - argument_list('a, b, *args, c'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - ], - ), - ( - argument_list('a, b, *args, c, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b, /, *, c, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b, /, c, *, d, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list( - ( - 'a: str, b: int, /, c: float, d: list,' - ' *, e: tuple, f: dict, **kwargs: set' - ), + +@pytest.mark.parametrize( + 'ast_arguments_list,expected', + [ + ( + argument_list('a'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], ), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'str', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.NORMAL, - None, - 'float', - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.NORMAL, - None, - 'list', - ), - PythonFunctionArgument( - 'e', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'tuple', - ), - PythonFunctionArgument( - 'f', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'dict', - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - 'set', - ), - ], - ), - ( - argument_list( - ( - 'a: str, b: int, /, c: float, d: list, *arg' - 's: bytes, e: tuple, f: dict, **kwargs: set' - ), + ( + argument_list('a: str'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + ], ), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'str', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.NORMAL, - None, - 'float', - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.NORMAL, - None, - 'list', - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - 'bytes', - ), - PythonFunctionArgument( - 'e', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'tuple', - ), - PythonFunctionArgument( - 'f', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'dict', - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - 'set', - ), - ], - ), - ( - argument_list( - ( - 'a: str, b: int, /, *args: bytes, ' - 'c: tuple, d: dict, **kwargs: set' - ), + ( + argument_list('a: str | int'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str | int', + ), + ], ), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'str', + ( + argument_list('a: str, b'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + ), + ( + argument_list('a: str, b: int'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + ], + ), + ( + argument_list('a, b: int'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + ], + ), + ( + argument_list('a, b, *args'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ), + ( + argument_list('a: int, b, *args'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ), + ( + argument_list('a, b: str, *args'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ), + ( + argument_list('a: int, b: str, *args'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + ], + ), + ( + argument_list('a: int, b: str, *args: float'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'str', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + 'float', + ), + ], + ), + ( + argument_list('a: int, b, *args: float'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + 'float', + ), + ], + ), + ( + argument_list('a: int, *args: float'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + 'float', + ), + ], + ), + ( + argument_list('a: int, /, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a: int, **kwargs: str'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + 'str', + ), + ], + ), + ( + argument_list('a: int, /, b, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a: int, /, b'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + ), + ( + argument_list('a: int, /, b, *, c'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ), + ( + argument_list('a, b, *, c'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ), + ( + argument_list('a, b, *args, c'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + ], + ), + ( + argument_list('a, b, *args, c, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b, /, *, c, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b, /, c, *, d, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list( + ( + 'a: str, b: int, /, c: float, d: list,' + ' *, e: tuple, f: dict, **kwargs: set' + ), ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'str', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.NORMAL, + None, + 'float', + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.NORMAL, + None, + 'list', + ), + PythonFunctionArgument( + 'e', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'tuple', + ), + PythonFunctionArgument( + 'f', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'dict', + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + 'set', + ), + ], + ), + ( + argument_list( + ( + 'a: str, b: int, /, c: float, d: list, *arg' + 's: bytes, e: tuple, f: dict, **kwargs: set' + ), ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - 'bytes', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'str', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.NORMAL, + None, + 'float', + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.NORMAL, + None, + 'list', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + 'bytes', + ), + PythonFunctionArgument( + 'e', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'tuple', + ), + PythonFunctionArgument( + 'f', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'dict', + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + 'set', + ), + ], + ), + ( + argument_list( + ( + 'a: str, b: int, /, *args: bytes, ' + 'c: tuple, d: dict, **kwargs: set' + ), ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'tuple', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'str', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + 'bytes', + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'tuple', + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'dict', + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + 'set', + ), + ], + ), + ( + argument_list( + "a = 1, b = 'a', /, *args, c = None, d = True, **kwargs", ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'dict', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + '1', + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + "'a'", + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + 'None', + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list( + "a, b = 'a', /, *args, c = None, d = True, **kwargs" ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - 'set', - ), - ], - ), - ( - argument_list( - 'a = 1, b = \'a\', /, *args, c = None, d = True, **kwargs', - ), [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - '1', - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - '\'a\'', - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - 'None', - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b = \'a\', /, *args, c = None, d = True, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - '\'a\'', - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - 'None', - None - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b , /, *args, c = None, d = True, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - 'None', - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b , /, *args, c, d = True, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - 'True', - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b , /, *args, c, d, **kwargs'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a, b , /, *args, c = None, d, **kwargs'), [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'args', - PythonArgumentKind.VARARG, - None, - None, - ), - PythonFunctionArgument( - 'c', - PythonArgumentKind.KEYWORD_ONLY, - 'None', - None, - ), - PythonFunctionArgument( - 'd', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, - ), - PythonFunctionArgument( - 'kwargs', - PythonArgumentKind.KWARGS, - None, - None, - ), - ], - ), - ( - argument_list('a = 1'), - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - None, - ), - ], - ), -]) + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + "'a'", + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', PythonArgumentKind.KEYWORD_ONLY, 'None', None + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b , /, *args, c = None, d = True, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + 'None', + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b , /, *args, c, d = True, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + 'True', + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b , /, *args, c, d, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a, b , /, *args, c = None, d, **kwargs'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'args', + PythonArgumentKind.VARARG, + None, + None, + ), + PythonFunctionArgument( + 'c', + PythonArgumentKind.KEYWORD_ONLY, + 'None', + None, + ), + PythonFunctionArgument( + 'd', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), + PythonFunctionArgument( + 'kwargs', + PythonArgumentKind.KWARGS, + None, + None, + ), + ], + ), + ( + argument_list('a = 1'), + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + None, + ), + ], + ), + ], +) def test_PythonASTArgumentsListParser_to_argument_list( ast_arguments_list, expected, ): - assert PythonASTArgumentsListParser( - ast_arguments_list - ).to_argument_list() == expected + assert ( + PythonASTArgumentsListParser(ast_arguments_list).to_argument_list() + == expected + ) diff --git a/tests/unit/core/python/arguments/test_PythonFunctionArgument.py b/tests/unit/core/python/arguments/test_PythonFunctionArgument.py index ec6747d..0652165 100644 --- a/tests/unit/core/python/arguments/test_PythonFunctionArgument.py +++ b/tests/unit/core/python/arguments/test_PythonFunctionArgument.py @@ -12,16 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, PythonArgumentKind, + PythonFunctionArgument, ) from src.jcloud_docsgen.exceptions import ( - InvalidPythonIdentifierError, InvalidPythonAnnotationError, + InvalidPythonIdentifierError, PythonArgumentStructureError, ) -import pytest + @pytest.mark.parametrize( 'name,kind,default,annotation,expected_exception,expected_exception_msg', @@ -32,7 +34,7 @@ import pytest None, None, TypeError, - 'expected \'str\', got \'NoneType\'', + "expected 'str', got 'NoneType'", ), ( 1, @@ -40,7 +42,7 @@ import pytest None, None, TypeError, - 'expected \'str\', got \'int\'', + "expected 'str', got 'int'", ), ( 42, @@ -48,7 +50,7 @@ import pytest None, None, TypeError, - 'expected \'str\', got \'int\'', + "expected 'str', got 'int'", ), ( 4.2, @@ -56,7 +58,7 @@ import pytest None, None, TypeError, - 'expected \'str\', got \'float\'', + "expected 'str', got 'float'", ), ( 4.2, @@ -64,7 +66,7 @@ import pytest None, None, TypeError, - 'expected \'str\', got \'float\'', + "expected 'str', got 'float'", ), ( 'a', @@ -72,7 +74,7 @@ import pytest 1, None, TypeError, - 'expected either \'str\' or \'NoneType\', got \'int\'', + "expected either 'str' or 'NoneType', got 'int'", ), ( 'a', @@ -80,7 +82,7 @@ import pytest None, 1, TypeError, - 'expected either \'str\' or \'NoneType\', got \'int\'', + "expected either 'str' or 'NoneType', got 'int'", ), ( 'a', @@ -88,7 +90,7 @@ import pytest None, None, TypeError, - 'expected \'PythonArgumentKind\', got \'int\'', + "expected 'PythonArgumentKind', got 'int'", ), ( 'a', @@ -384,220 +386,244 @@ def test_PythonFunctionArgument_exceptions( PythonFunctionArgument(name, kind, default, annotation) assert str(exc_info.value) == expected_exception_msg -@pytest.mark.parametrize('name', [ - 'a', - '_a', - 'a1', - 'a0', - 'a_', - '_', - '_abc', - 'abc', - 'abc_', - 'match', - 'case', - 'type', - 'ä', - 'none', - 'true', - 'false', -]) -@pytest.mark.parametrize('kind', [ - PythonArgumentKind.NORMAL, - PythonArgumentKind.POSITIONAL_ONLY, - PythonArgumentKind.KEYWORD_ONLY, -]) -@pytest.mark.parametrize('default', [ - None, - 'x', - '1', - None, -]) -@pytest.mark.parametrize('annotation', [ - None, - 'a', - 'list[int]', - '_', -]) + +@pytest.mark.parametrize( + 'name', + [ + 'a', + '_a', + 'a1', + 'a0', + 'a_', + '_', + '_abc', + 'abc', + 'abc_', + 'match', + 'case', + 'type', + 'ä', + 'none', + 'true', + 'false', + ], +) +@pytest.mark.parametrize( + 'kind', + [ + PythonArgumentKind.NORMAL, + PythonArgumentKind.POSITIONAL_ONLY, + PythonArgumentKind.KEYWORD_ONLY, + ], +) +@pytest.mark.parametrize( + 'default', + [ + None, + 'x', + '1', + None, + ], +) +@pytest.mark.parametrize( + 'annotation', + [ + None, + 'a', + 'list[int]', + '_', + ], +) def test_PythonFunctionArgument(name, kind, default, annotation): PythonFunctionArgument(name, kind, default, annotation) -@pytest.mark.parametrize('name', [ - 'a', - '_a', - 'a1', - 'a0', - 'a_', - '_', - '_abc', - 'abc', - 'abc_', - 'match', - 'case', - 'type', - 'ä', - 'none', - 'true', - 'false', -]) -@pytest.mark.parametrize('kind', [ - PythonArgumentKind.VARARG, - PythonArgumentKind.KWARGS, -]) -@pytest.mark.parametrize('annotation', [ - None, - 'a', - 'list[int]', - '_', -]) + +@pytest.mark.parametrize( + 'name', + [ + 'a', + '_a', + 'a1', + 'a0', + 'a_', + '_', + '_abc', + 'abc', + 'abc_', + 'match', + 'case', + 'type', + 'ä', + 'none', + 'true', + 'false', + ], +) +@pytest.mark.parametrize( + 'kind', + [ + PythonArgumentKind.VARARG, + PythonArgumentKind.KWARGS, + ], +) +@pytest.mark.parametrize( + 'annotation', + [ + None, + 'a', + 'list[int]', + '_', + ], +) def test_PythonFunctionArgument_asterik(name, kind, annotation): PythonFunctionArgument(name, kind, None, annotation) -@pytest.mark.parametrize('argument,expected', [ - ( - PythonFunctionArgument( + +@pytest.mark.parametrize( + 'argument,expected', + [ + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + None, + ), 'a', - PythonArgumentKind.NORMAL, - None, - None, ), - 'a', - ), - ( - PythonFunctionArgument( + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + None, + ), + 'a = 1', + ), + ( + PythonFunctionArgument( + 'a', PythonArgumentKind.NORMAL, None, 'int' + ), + 'a: int', + ), + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + '1', + 'int', + ), + 'a: int = 1', + ), + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + None, + ), 'a', - PythonArgumentKind.NORMAL, - '1', - None, ), - 'a = 1', - ), - ( - PythonFunctionArgument( + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + '1', + None, + ), + 'a = 1', + ), + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + None, + 'int', + ), + 'a: int', + ), + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.POSITIONAL_ONLY, + '1', + 'int', + ), + 'a: int = 1', + ), + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + None, + None, + ), 'a', - PythonArgumentKind.NORMAL, - None, - 'int' ), - 'a: int', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - '1', - 'int', + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + '1', + None, + ), + 'a = 1', ), - 'a: int = 1', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - None, + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + None, + 'int', + ), + 'a: int', ), - 'a', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - '1', - None, + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KEYWORD_ONLY, + '1', + 'int', + ), + 'a: int = 1', ), - 'a = 1', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - None, - 'int', + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.VARARG, + None, + None, + ), + '*a', ), - 'a: int', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.POSITIONAL_ONLY, - '1', - 'int', + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.VARARG, + None, + 'int', + ), + '*a: int', ), - 'a: int = 1', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - None, - None, + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KWARGS, + None, + None, + ), + '**a', ), - 'a', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - '1', - None, + ( + PythonFunctionArgument( + 'a', + PythonArgumentKind.KWARGS, + None, + 'int', + ), + '**a: int', ), - 'a = 1', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - None, - 'int', - ), - 'a: int', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KEYWORD_ONLY, - '1', - 'int', - ), - 'a: int = 1', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.VARARG, - None, - None, - ), - '*a', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.VARARG, - None, - 'int', - ), - '*a: int', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KWARGS, - None, - None, - ), - '**a', - ), - ( - PythonFunctionArgument( - 'a', - PythonArgumentKind.KWARGS, - None, - 'int', - ), - '**a: int', - ), -]) + ], +) def test_PythonFunctionArgument_signature_repr(argument, expected): assert argument.signature_repr() == expected diff --git a/tests/unit/core/python/definitions/test_PythonClassDefinition.py b/tests/unit/core/python/definitions/test_PythonClassDefinition.py index 6bd3c51..61ec8ac 100644 --- a/tests/unit/core/python/definitions/test_PythonClassDefinition.py +++ b/tests/unit/core/python/definitions/test_PythonClassDefinition.py @@ -12,44 +12,49 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.definitions import ( - PythonFunctionDefinition, - PythonClassDefinition, -) +import pytest + from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, PythonArgumentKind, + PythonFunctionArgument, +) +from src.jcloud_docsgen.core.python.definitions import ( + PythonClassDefinition, + PythonFunctionDefinition, ) from src.jcloud_docsgen.core.python.docstrings import PythonDocstring from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError from tests.utils.ast_node import ast_node -import pytest -@pytest.mark.parametrize('definition,expected', [ - ( - PythonClassDefinition( - 'A', - [], - None, - None, - [], - ), - 'PythonClassDefinition(\'A\', [], None, None, [])', - ), - ( - PythonClassDefinition( - 'A', - [], - None, - PythonDocstring('Hello, World!'), - [], + +@pytest.mark.parametrize( + 'definition,expected', + [ + ( + PythonClassDefinition( + 'A', + [], + None, + None, + [], + ), + "PythonClassDefinition('A', [], None, None, [])", ), ( - 'PythonClassDefinition(\'A\', [], None, ' - 'PythonDocstring(\'Hello, World!\'), [])' + PythonClassDefinition( + 'A', + [], + None, + PythonDocstring('Hello, World!'), + [], + ), + ( + "PythonClassDefinition('A', [], None, " + "PythonDocstring('Hello, World!'), [])" + ), ), - ), -]) + ], +) def test_PythonDefinition_string_representation(definition, expected): assert repr(definition) == expected @@ -364,129 +369,132 @@ def test_PythonFunctionDefinition_exceptions( assert str(exc_info.value) == expected_exception_message -@pytest.mark.parametrize('node,expected', [ - ( - ast_node( - ( - '@decorator\nclass Class(BaseClass1, BaseClass2)' - ':\n\tdef __init__(self, value: object) -> None:' - '\n\t\tself._value = value\n\n\t@property\n\tdef' - ' value(self) -> object:\n\t\treturn self._value' +@pytest.mark.parametrize( + 'node,expected', + [ + ( + ast_node( + ( + '@decorator\nclass Class(BaseClass1, BaseClass2)' + ':\n\tdef __init__(self, value: object) -> None:' + '\n\t\tself._value = value\n\n\t@property\n\tdef' + ' value(self) -> object:\n\t\treturn self._value' + ), + ), + PythonClassDefinition( + 'Class', + ['BaseClass1', 'BaseClass2'], + None, + ['decorator'], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + PythonFunctionArgument( + 'value', + PythonArgumentKind.NORMAL, + None, + 'object', + ), + ], + 'None', + None, + [], + ), + PythonFunctionDefinition( + 'value', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + 'object', + None, + ['property'], + ), + ], ), ), - PythonClassDefinition( - 'Class', - ['BaseClass1', 'BaseClass2'], - None, - ['decorator'], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - PythonFunctionArgument( - 'value', - PythonArgumentKind.NORMAL, - None, - 'object', - ), - ], - 'None', - None, - [], - ), - PythonFunctionDefinition( - 'value', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - 'object', - None, - ['property'], - ), - ], + ( + ast_node('class Class: ...'), + PythonClassDefinition( + 'Class', + [], + None, + [], + [], + ), ), - ), - ( - ast_node('class Class: ...'), - PythonClassDefinition( - 'Class', - [], - None, - [], - [], + ( + ast_node("class Class: '''docstring'''"), + PythonClassDefinition( + 'Class', + [], + PythonDocstring('docstring'), + [], + [], + ), ), - ), - ( - ast_node('class Class: \'\'\'docstring\'\'\''), - PythonClassDefinition( - 'Class', - [], - PythonDocstring('docstring'), - [], - [], + ( + ast_node('class Class:\n\tdef __init__(self): ...'), + PythonClassDefinition( + 'Class', + [], + None, + [], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ) + ], + None, + None, + [], + ), + ], + ), ), - ), - ( - ast_node('class Class:\n\tdef __init__(self): ...'), - PythonClassDefinition( - 'Class', - [], - None, - [], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ) - ], - None, - None, - [], - ), - ], + ( + ast_node("class Class:\n\t'''doc'''\n\tdef __init__(self): ..."), + PythonClassDefinition( + 'Class', + [], + PythonDocstring('doc'), + [], + [ + PythonFunctionDefinition( + '__init__', + [ + PythonFunctionArgument( + 'self', + PythonArgumentKind.NORMAL, + None, + None, + ), + ], + None, + None, + [], + ), + ], + ), ), - ), - ( - ast_node('class Class:\n\t\'\'\'doc\'\'\'\n\tdef __init__(self): ...'), - PythonClassDefinition( - 'Class', - [], - PythonDocstring('doc'), - [], - [ - PythonFunctionDefinition( - '__init__', - [ - PythonFunctionArgument( - 'self', - PythonArgumentKind.NORMAL, - None, - None, - ), - ], - None, - None, - [], - ), - ], - ), - ), -]) + ], +) def test_PythonDefinition_from_node(node, expected): assert PythonClassDefinition.from_node(node) == expected diff --git a/tests/unit/core/python/definitions/test_PythonDefinition.py b/tests/unit/core/python/definitions/test_PythonDefinition.py index 57efca3..3b87e32 100644 --- a/tests/unit/core/python/definitions/test_PythonDefinition.py +++ b/tests/unit/core/python/definitions/test_PythonDefinition.py @@ -12,29 +12,34 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from src.jcloud_docsgen.core.python.definitions import PythonDefinition from src.jcloud_docsgen.core.python.docstrings import PythonDocstring from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError -import pytest -@pytest.mark.parametrize('definition,expected', [ - ( - PythonDefinition( - 'a', - None, - [], + +@pytest.mark.parametrize( + 'definition,expected', + [ + ( + PythonDefinition( + 'a', + None, + [], + ), + "PythonDefinition('a', None, [])", ), - 'PythonDefinition(\'a\', None, [])', - ), - ( - PythonDefinition( - 'a', - PythonDocstring('Hello, World!'), - [], + ( + PythonDefinition( + 'a', + PythonDocstring('Hello, World!'), + [], + ), + "PythonDefinition('a', PythonDocstring('Hello, World!'), [])", ), - 'PythonDefinition(\'a\', PythonDocstring(\'Hello, World!\'), [])', - ), -]) + ], +) def test_PythonDefinition_string_representation(definition, expected): assert repr(definition) == expected @@ -280,164 +285,167 @@ def test_PythonDefinition_exceptions( assert str(exc_info.value) == expected_exception_message -@pytest.mark.parametrize('definition1,definition2,expected', [ - ( - PythonDefinition( - 'a', - None, - [], +@pytest.mark.parametrize( + 'definition1,definition2,expected', + [ + ( + PythonDefinition( + 'a', + None, + [], + ), + PythonDefinition( + 'a', + None, + [], + ), + True, ), - PythonDefinition( - 'a', - None, - [], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + [], + ), + PythonDefinition( + 'a', + PythonDocstring('doc'), + [], + ), + True, ), - True, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - [], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + ['a'], + ), + PythonDefinition( + 'a', + PythonDocstring('doc'), + ['a'], + ), + True, ), - PythonDefinition( - 'a', - PythonDocstring('doc'), - [], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + ['a', 'b'], + ), + PythonDefinition( + 'a', + PythonDocstring('doc'), + ['a', 'b'], + ), + True, ), - True, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - ['a'], + ( + PythonDefinition( + 'a', + None, + [], + ), + PythonDefinition( + 'b', + None, + [], + ), + False, ), - PythonDefinition( - 'a', - PythonDocstring('doc'), - ['a'], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + [], + ), + PythonDefinition( + 'a', + None, + [], + ), + False, ), - True, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - ['a', 'b'], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + [], + ), + PythonDefinition( + 'a', + PythonDocstring('docs'), + [], + ), + False, ), - PythonDefinition( - 'a', - PythonDocstring('doc'), - ['a', 'b'], + ( + PythonDefinition( + 'a', + None, + ['a'], + ), + PythonDefinition( + 'a', + None, + ['b'], + ), + False, ), - True, - ), - ( - PythonDefinition( - 'a', - None, - [], + ( + PythonDefinition( + 'a', + None, + ['a'], + ), + PythonDefinition( + 'a', + None, + [], + ), + False, ), - PythonDefinition( - 'b', - None, - [], + ( + PythonDefinition( + 'a', + None, + ['a'], + ), + PythonDefinition( + 'a', + None, + ['a', 'b'], + ), + False, ), - False, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - [], + ( + PythonDefinition( + 'a', + None, + ['b', 'a'], + ), + PythonDefinition( + 'a', + None, + ['a', 'b'], + ), + False, ), - PythonDefinition( - 'a', - None, - [], + ( + PythonDefinition( + 'a', + PythonDocstring('doc'), + [], + ), + PythonDefinition( + 'b', + None, + ['a', 'b'], + ), + False, ), - False, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - [], - ), - PythonDefinition( - 'a', - PythonDocstring('docs'), - [], - ), - False, - ), - ( - PythonDefinition( - 'a', - None, - ['a'], - ), - PythonDefinition( - 'a', - None, - ['b'], - ), - False, - ), - ( - PythonDefinition( - 'a', - None, - ['a'], - ), - PythonDefinition( - 'a', - None, - [], - ), - False, - ), - ( - PythonDefinition( - 'a', - None, - ['a'], - ), - PythonDefinition( - 'a', - None, - ['a', 'b'], - ), - False, - ), - ( - PythonDefinition( - 'a', - None, - ['b', 'a'], - ), - PythonDefinition( - 'a', - None, - ['a', 'b'], - ), - False, - ), - ( - PythonDefinition( - 'a', - PythonDocstring('doc'), - [], - ), - PythonDefinition( - 'b', - None, - ['a', 'b'], - ), - False, - ), -]) + ], +) def test_PythonDefinition___eq__(definition1, definition2, expected): assert (definition1 == definition2) == expected assert (definition2 == definition1) == expected diff --git a/tests/unit/core/python/definitions/test_PythonFunctionDefinition.py b/tests/unit/core/python/definitions/test_PythonFunctionDefinition.py index c119ecb..f385196 100644 --- a/tests/unit/core/python/definitions/test_PythonFunctionDefinition.py +++ b/tests/unit/core/python/definitions/test_PythonFunctionDefinition.py @@ -12,41 +12,46 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.definitions import PythonFunctionDefinition +import pytest + from src.jcloud_docsgen.core.python.arguments import ( - PythonFunctionArgument, PythonArgumentKind, + PythonFunctionArgument, ) +from src.jcloud_docsgen.core.python.definitions import PythonFunctionDefinition from src.jcloud_docsgen.core.python.docstrings import PythonDocstring from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError from tests.utils.ast_node import ast_node -import pytest -@pytest.mark.parametrize('definition,expected', [ - ( - PythonFunctionDefinition( - 'a', - [], - None, - None, - [], - ), - 'PythonFunctionDefinition(\'a\', [], None, None, [])', - ), - ( - PythonFunctionDefinition( - 'a', - [], - None, - PythonDocstring('Hello, World!'), - [], + +@pytest.mark.parametrize( + 'definition,expected', + [ + ( + PythonFunctionDefinition( + 'a', + [], + None, + None, + [], + ), + "PythonFunctionDefinition('a', [], None, None, [])", ), ( - 'PythonFunctionDefinition(\'a\', [], None,' - ' PythonDocstring(\'Hello, World!\'), [])' + PythonFunctionDefinition( + 'a', + [], + None, + PythonDocstring('Hello, World!'), + [], + ), + ( + "PythonFunctionDefinition('a', [], None," + " PythonDocstring('Hello, World!'), [])" + ), ), - ), -]) + ], +) def test_PythonDefinition_string_representation(definition, expected): assert repr(definition) == expected @@ -57,295 +62,296 @@ def test_PythonDefinition_string_representation(definition, expected): 'ed_exception,expected_exception_message' ), [ - ( - '', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier', - ), - ( - '.', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: .', - ), - ( - '#', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: #', - ), - ( - '1a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: 1a', - ), - ( - '1_', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: 1_', - ), - ( - '1,', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: 1,', - ), - ( - ',', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: ,', - ), - ( - ':', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: :', - ), - ( - '-', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: -', - ), - ( - ';', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: ;', - ), - ( - '|', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: |', - ), - ( - '<', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: <', - ), - ( - '>', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: >', - ), - ( - 'a,', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a,', - ), - ( - ',a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: ,a', - ), - ( - 'a:', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a:', - ), - ( - ':a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: :a', - ), - ( - 'a-', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a-', - ), - ( - '-a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: -a', - ), - ( - 'a;', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a;', - ), - ( - ';a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: ;a', - ), - ( - 'a|', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a|', - ), - ( - '|a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: |a', - ), - ( - 'a<', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a<', - ), - ( - '', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: a>', - ), - ( - '>a', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: >a', - ), - ( - 'class', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: class', - ), - ( - 'def', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: def', - ), - ( - 'lambda', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: lambda', - ), - ( - 'None', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: None', - ), - ( - 'True', - [], - None, - None, - [], - InvalidPythonIdentifierError, - 'invalid identifier: True', - ), -]) + ( + '', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier', + ), + ( + '.', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: .', + ), + ( + '#', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: #', + ), + ( + '1a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: 1a', + ), + ( + '1_', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: 1_', + ), + ( + '1,', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: 1,', + ), + ( + ',', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: ,', + ), + ( + ':', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: :', + ), + ( + '-', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: -', + ), + ( + ';', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: ;', + ), + ( + '|', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: |', + ), + ( + '<', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: <', + ), + ( + '>', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: >', + ), + ( + 'a,', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a,', + ), + ( + ',a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: ,a', + ), + ( + 'a:', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a:', + ), + ( + ':a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: :a', + ), + ( + 'a-', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a-', + ), + ( + '-a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: -a', + ), + ( + 'a;', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a;', + ), + ( + ';a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: ;a', + ), + ( + 'a|', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a|', + ), + ( + '|a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: |a', + ), + ( + 'a<', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a<', + ), + ( + '', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: a>', + ), + ( + '>a', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: >a', + ), + ( + 'class', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: class', + ), + ( + 'def', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: def', + ), + ( + 'lambda', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: lambda', + ), + ( + 'None', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: None', + ), + ( + 'True', + [], + None, + None, + [], + InvalidPythonIdentifierError, + 'invalid identifier: True', + ), + ], +) def test_PythonFunctionDefinition_exceptions( name, args, @@ -360,100 +366,106 @@ def test_PythonFunctionDefinition_exceptions( assert str(exc_info.value) == expected_exception_message -@pytest.mark.parametrize('node,expected', [ - ( - ast_node('def add(a: int, b: int) -> int: return a + b'), - PythonFunctionDefinition( - 'add', [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - ], - 'int', - None, - [], - ), - ), - ( - ast_node('@decorator\ndef add(a: int, b: int) -> int: return a + b'), - PythonFunctionDefinition( - 'add', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - ], - 'int', - None, - ['decorator'], - ), - ), - ( - ast_node( - ( - '@decorator1\n@decorator2\ndef add(a' - ': int, b: int) -> int: return a + b' +@pytest.mark.parametrize( + 'node,expected', + [ + ( + ast_node('def add(a: int, b: int) -> int: return a + b'), + PythonFunctionDefinition( + 'add', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + ], + 'int', + None, + [], ), ), - PythonFunctionDefinition( - 'add', - [ - PythonFunctionArgument( - 'a', - PythonArgumentKind.NORMAL, - None, - 'int', + ( + ast_node( + '@decorator\ndef add(a: int, b: int) -> int: return a + b' + ), + PythonFunctionDefinition( + 'add', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + ], + 'int', + None, + ['decorator'], + ), + ), + ( + ast_node( + ( + '@decorator1\n@decorator2\ndef add(a' + ': int, b: int) -> int: return a + b' ), - PythonFunctionArgument( - 'b', - PythonArgumentKind.NORMAL, - None, - 'int', - ), - ], - 'int', - None, - ['decorator1', 'decorator2'], + ), + PythonFunctionDefinition( + 'add', + [ + PythonFunctionArgument( + 'a', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + PythonFunctionArgument( + 'b', + PythonArgumentKind.NORMAL, + None, + 'int', + ), + ], + 'int', + None, + ['decorator1', 'decorator2'], + ), ), - ), - ( - ast_node('def func(): ...'), - PythonFunctionDefinition( - 'func', - [], - None, - None, - [], + ( + ast_node('def func(): ...'), + PythonFunctionDefinition( + 'func', + [], + None, + None, + [], + ), ), - ), - ( - ast_node('@decorator\ndef func(): ...'), - PythonFunctionDefinition( - 'func', - [], - None, - None, - ['decorator'], + ( + ast_node('@decorator\ndef func(): ...'), + PythonFunctionDefinition( + 'func', + [], + None, + None, + ['decorator'], + ), ), - ), -]) + ], +) def test_PythonDefinition_from_node(node, expected): assert PythonFunctionDefinition.from_node(node) == expected diff --git a/tests/unit/core/python/namespaces/test_PythonModuleNamespace.py b/tests/unit/core/python/namespaces/test_PythonModuleNamespace.py index 9525f28..7433a84 100644 --- a/tests/unit/core/python/namespaces/test_PythonModuleNamespace.py +++ b/tests/unit/core/python/namespaces/test_PythonModuleNamespace.py @@ -12,36 +12,53 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace import pytest +from src.jcloud_docsgen.core.python.namespaces import PythonModuleNamespace + + class StrSubclass(str): ... -@pytest.mark.parametrize('namespace,expected_name', [ - (PythonModuleNamespace('a'), 'a'), - (PythonModuleNamespace('1'), '1'), - (PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')), -]) + +@pytest.mark.parametrize( + 'namespace,expected_name', + [ + (PythonModuleNamespace('a'), 'a'), + (PythonModuleNamespace('1'), '1'), + (PythonModuleNamespace(StrSubclass('a')), StrSubclass('a')), + ], +) def test_PythonModuleNamespace_name_attribute(namespace, expected_name): assert namespace.name == expected_name -@pytest.mark.parametrize('namespace1,namespace2,expected', [ - (PythonModuleNamespace('a'), PythonModuleNamespace('a'), True), - (PythonModuleNamespace('b'), PythonModuleNamespace('b'), True), - (PythonModuleNamespace('1'), PythonModuleNamespace('1'), True), - (PythonModuleNamespace('42'), PythonModuleNamespace('42'), True), - (PythonModuleNamespace('a'), PythonModuleNamespace('b'), False), - (PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False), - (PythonModuleNamespace('1'), PythonModuleNamespace('a'), False), -]) + +@pytest.mark.parametrize( + 'namespace1,namespace2,expected', + [ + (PythonModuleNamespace('a'), PythonModuleNamespace('a'), True), + (PythonModuleNamespace('b'), PythonModuleNamespace('b'), True), + (PythonModuleNamespace('1'), PythonModuleNamespace('1'), True), + (PythonModuleNamespace('42'), PythonModuleNamespace('42'), True), + (PythonModuleNamespace('a'), PythonModuleNamespace('b'), False), + (PythonModuleNamespace('0'), PythonModuleNamespace('-0'), False), + (PythonModuleNamespace('1'), PythonModuleNamespace('a'), False), + ], +) def test_PythonModuleNamespace___eq__(namespace1, namespace2, expected): assert (namespace1 == namespace2) == expected assert (namespace2 == namespace1) == expected -@pytest.mark.parametrize('namespace,expected', [ - (PythonModuleNamespace('a'), 'PythonModuleNamespace(\'a\')'), - (PythonModuleNamespace('1'), 'PythonModuleNamespace(\'1\')'), - (PythonModuleNamespace(StrSubclass('a')), 'PythonModuleNamespace(\'a\')'), -]) + +@pytest.mark.parametrize( + 'namespace,expected', + [ + (PythonModuleNamespace('a'), "PythonModuleNamespace('a')"), + (PythonModuleNamespace('1'), "PythonModuleNamespace('1')"), + ( + PythonModuleNamespace(StrSubclass('a')), + "PythonModuleNamespace('a')", + ), + ], +) def test_PythonModuleNamespace_string_representation(namespace, expected): assert repr(namespace) == expected diff --git a/tests/unit/core/python/namespaces/test_PythonNamespace.py b/tests/unit/core/python/namespaces/test_PythonNamespace.py index 440221b..e4ee640 100644 --- a/tests/unit/core/python/namespaces/test_PythonNamespace.py +++ b/tests/unit/core/python/namespaces/test_PythonNamespace.py @@ -12,23 +12,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.namespaces import PythonNamespace import pytest +from src.jcloud_docsgen.core.python.namespaces import PythonNamespace + + class StrSubclass(str): ... -@pytest.mark.parametrize('namespace,expected_name', [ - (PythonNamespace('a'), 'a'), - (PythonNamespace('1'), '1'), - (PythonNamespace(StrSubclass('a')), StrSubclass('a')), -]) + +@pytest.mark.parametrize( + 'namespace,expected_name', + [ + (PythonNamespace('a'), 'a'), + (PythonNamespace('1'), '1'), + (PythonNamespace(StrSubclass('a')), StrSubclass('a')), + ], +) def test_PythonNamespace_name_attribute(namespace, expected_name): assert namespace.name == expected_name -@pytest.mark.parametrize('namespace,expected', [ - (PythonNamespace('a'), 'PythonNamespace(\'a\')'), - (PythonNamespace('1'), 'PythonNamespace(\'1\')'), - (PythonNamespace(StrSubclass('a')), 'PythonNamespace(\'a\')'), -]) + +@pytest.mark.parametrize( + 'namespace,expected', + [ + (PythonNamespace('a'), "PythonNamespace('a')"), + (PythonNamespace('1'), "PythonNamespace('1')"), + (PythonNamespace(StrSubclass('a')), "PythonNamespace('a')"), + ], +) def test_PythonNamespace_string_representation(namespace, expected): assert repr(namespace) == expected diff --git a/tests/unit/core/python/namespaces/test_PythonPackageNamespace.py b/tests/unit/core/python/namespaces/test_PythonPackageNamespace.py index e8a5af9..a768e7e 100644 --- a/tests/unit/core/python/namespaces/test_PythonPackageNamespace.py +++ b/tests/unit/core/python/namespaces/test_PythonPackageNamespace.py @@ -12,48 +12,58 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.core.python.namespaces import ( - PythonPackageNamespace, - PythonModuleNamespace, -) import pytest -from src.jcloud_docsgen.exceptions import ( - NamespaceNotFoundError, - InvalidNamespaceError, + +from src.jcloud_docsgen.core.python.namespaces import ( + PythonModuleNamespace, + PythonPackageNamespace, ) +from src.jcloud_docsgen.exceptions import ( + InvalidNamespaceError, + NamespaceNotFoundError, +) + class StrSubclass(str): ... -@pytest.mark.parametrize('namespace,expected_name', [ - ( - PythonPackageNamespace( + +@pytest.mark.parametrize( + 'namespace,expected_name', + [ + ( + PythonPackageNamespace( + 'a', + [], + ), 'a', - [], ), - 'a', - ), - ( - PythonPackageNamespace( + ( + PythonPackageNamespace( + '1', + [], + ), '1', - [], ), - '1', - ), - ( - PythonPackageNamespace( + ( + PythonPackageNamespace( + StrSubclass('a'), + [], + ), StrSubclass('a'), - [], ), - StrSubclass('a'), - ), -]) + ], +) def test_PythonPackageNamespace_name_attribute(namespace, expected_name): assert namespace.name == expected_name + namespace_b = PythonModuleNamespace('b') -namespace_a = PythonPackageNamespace('a', [ - namespace_b, -]) +namespace_a = PythonPackageNamespace( + 'a', + [ + namespace_b, + ], +) namespace_c = PythonModuleNamespace('c') namespace_k = PythonModuleNamespace('k') namespace_j = PythonPackageNamespace('j', [namespace_k]) @@ -64,47 +74,51 @@ namespace_f = PythonPackageNamespace('f', [namespace_g]) namespace_e = PythonPackageNamespace('e', [namespace_f]) namespace_d = PythonPackageNamespace('d', [namespace_e]) -@pytest.mark.parametrize('namespace,sub_namespaces,expected', [ - ( - PythonPackageNamespace( - 'name', - [namespace_a, namespace_c], + +@pytest.mark.parametrize( + 'namespace,sub_namespaces,expected', + [ + ( + PythonPackageNamespace( + 'name', + [namespace_a, namespace_c], + ), + ['c'], + namespace_c, ), - ['c'], - namespace_c, - ), - ( - PythonPackageNamespace( - 'name', - [namespace_a, namespace_c], + ( + PythonPackageNamespace( + 'name', + [namespace_a, namespace_c], + ), + ['a'], + namespace_a, ), - ['a'], - namespace_a, - ), - ( - PythonPackageNamespace( - 'name', - [namespace_a, namespace_c], + ( + PythonPackageNamespace( + 'name', + [namespace_a, namespace_c], + ), + ['a', 'b'], + namespace_b, ), - ['a', 'b'], - namespace_b, - ), - ( - namespace_d, - ['e', 'f', 'g', 'h', 'i'], - namespace_i, - ), - ( - namespace_d, - ['e', 'f', 'g', 'h', 'i', 'j'], - namespace_j, - ), - ( - namespace_d, - ['e', 'f', 'g', 'h', 'i', 'j', 'k'], - namespace_k, - ), -]) + ( + namespace_d, + ['e', 'f', 'g', 'h', 'i'], + namespace_i, + ), + ( + namespace_d, + ['e', 'f', 'g', 'h', 'i', 'j'], + namespace_j, + ), + ( + namespace_d, + ['e', 'f', 'g', 'h', 'i', 'j', 'k'], + namespace_k, + ), + ], +) def test_PythonPackageNamespace_namespace( namespace: PythonPackageNamespace, sub_namespaces, @@ -112,6 +126,7 @@ def test_PythonPackageNamespace_namespace( ): assert namespace.namespace(sub_namespaces) == expected + @pytest.mark.parametrize( 'namespace,sub_namespaces,expected_exception,expected_exception_msg', [ @@ -157,129 +172,145 @@ def test_PythonPackageNamespace_namespace_exceptions( namespace.namespace(sub_namespaces) assert str(exc_info.value) == expected_exception_msg -@pytest.mark.parametrize('namespace,expected', [ - ( - PythonPackageNamespace( - 'a', - [PythonModuleNamespace('b')], + +@pytest.mark.parametrize( + 'namespace,expected', + [ + ( + PythonPackageNamespace( + 'a', + [PythonModuleNamespace('b')], + ), + {'b': 'b'}, ), - {'b': 'b'}, - ), - ( - PythonPackageNamespace( - 'a', - [ - PythonModuleNamespace('b'), - PythonPackageNamespace( - 'c', - [PythonModuleNamespace('d')], - ), - ], + ( + PythonPackageNamespace( + 'a', + [ + PythonModuleNamespace('b'), + PythonPackageNamespace( + 'c', + [PythonModuleNamespace('d')], + ), + ], + ), + { + 'b': 'b', + 'c': {'d': 'd'}, + }, ), - { - 'b': 'b', - 'c': {'d': 'd'}, - }, - ), - ( - PythonPackageNamespace('a', []), - {}, - ), -]) + ( + PythonPackageNamespace('a', []), + {}, + ), + ], +) def test_PythonPackageNamespace_sub_namespace_names(namespace, expected): assert namespace.sub_namespace_names() == expected -@pytest.mark.parametrize('namespace1,namespace2,expected', [ - ( - PythonPackageNamespace( - 'a', - [PythonModuleNamespace('b')], + +@pytest.mark.parametrize( + 'namespace1,namespace2,expected', + [ + ( + PythonPackageNamespace( + 'a', + [PythonModuleNamespace('b')], + ), + PythonPackageNamespace( + 'a', + [PythonModuleNamespace('b')], + ), + True, ), - PythonPackageNamespace( - 'a', - [PythonModuleNamespace('b')], + ( + PythonPackageNamespace( + 'a', + [ + PythonModuleNamespace('b'), + PythonPackageNamespace( + 'c', + [PythonModuleNamespace('d')], + ), + ], + ), + PythonPackageNamespace( + 'a', + [ + PythonModuleNamespace('b'), + PythonPackageNamespace( + 'c', + [PythonModuleNamespace('d')], + ), + ], + ), + True, ), - True, - ), - ( - PythonPackageNamespace( - 'a', - [ - PythonModuleNamespace('b'), - PythonPackageNamespace( - 'c', - [PythonModuleNamespace('d')], - ), - ], + ( + PythonPackageNamespace('a', []), + PythonPackageNamespace('a', []), + True, ), - PythonPackageNamespace( - 'a', - [ - PythonModuleNamespace('b'), - PythonPackageNamespace( - 'c', - [PythonModuleNamespace('d')], - ), - ], + ( + PythonPackageNamespace('a', []), + PythonPackageNamespace('b', []), + False, ), - True, - ), - ( - PythonPackageNamespace('a', []), - PythonPackageNamespace('a', []), - True, - ), - ( - PythonPackageNamespace('a', []), - PythonPackageNamespace('b', []), - False, - ), -]) + ], +) def test_PythonPackageNamespace___eq__(namespace1, namespace2, expected): assert (namespace1 == namespace2) == expected assert (namespace2 == namespace1) == expected -@pytest.mark.parametrize('namespace,expected', [ - ( - PythonPackageNamespace('a', []), - 'PythonPackageNamespace(\'a\', [])', - ), - ( - PythonPackageNamespace('1', []), - 'PythonPackageNamespace(\'1\', [])', - ), - ( - PythonPackageNamespace(StrSubclass('a'), []), - 'PythonPackageNamespace(\'a\', [])', - ), - ( - namespace_a, - 'PythonPackageNamespace(\'a\', [PythonModuleNamespace(\'b\')])', - ), - ( - namespace_d, + +@pytest.mark.parametrize( + 'namespace,expected', + [ ( - 'PythonPackageNamespace(\'d\', [PythonPackageNamespac' - 'e(\'e\', [PythonPackageNamespace(\'f\', [PythonPacka' - 'geNamespace(\'g\', [PythonPackageNamespace(\'h\', [P' - 'ythonPackageNamespace(\'i\', [PythonPackageNamespace' - '(\'j\', [PythonModuleNamespace(\'k\')])])])])])])])' + PythonPackageNamespace('a', []), + "PythonPackageNamespace('a', [])", ), - ), -]) + ( + PythonPackageNamespace('1', []), + "PythonPackageNamespace('1', [])", + ), + ( + PythonPackageNamespace(StrSubclass('a'), []), + "PythonPackageNamespace('a', [])", + ), + ( + namespace_a, + "PythonPackageNamespace('a', [PythonModuleNamespace('b')])", + ), + ( + namespace_d, + ( + "PythonPackageNamespace('d', [PythonPackageNamespac" + "e('e', [PythonPackageNamespace('f', [PythonPacka" + "geNamespace('g', [PythonPackageNamespace('h', [P" + "ythonPackageNamespace('i', [PythonPackageNamespace" + "('j', [PythonModuleNamespace('k')])])])])])])])" + ), + ), + ], +) def test_PythonPackageNamespace_string_representation(namespace, expected): assert repr(namespace) == expected -@pytest.mark.parametrize('namespace,new_namespace,expected', [ - ( - PythonPackageNamespace('a', []), - PythonModuleNamespace('b'), - PythonPackageNamespace( - 'a', - [PythonModuleNamespace('b')], + +@pytest.mark.parametrize( + 'namespace,new_namespace,expected', + [ + ( + PythonPackageNamespace('a', []), + PythonModuleNamespace('b'), + PythonPackageNamespace( + 'a', + [PythonModuleNamespace('b')], + ), ), - ), -]) + ], +) def test_PythonPackageNamespace___getitem__( namespace, new_namespace, diff --git a/tests/unit/utils/test_assert_that_is_instance.py b/tests/unit/utils/test_assert_that_is_instance.py index 54d69b2..739b90b 100644 --- a/tests/unit/utils/test_assert_that_is_instance.py +++ b/tests/unit/utils/test_assert_that_is_instance.py @@ -12,51 +12,64 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.utils import assert_that_is_instance -import pytest import types +import pytest + +from src.jcloud_docsgen.utils import assert_that_is_instance + + class TestType: ... + + TestType.__name__ = 'NOT TestType' -@pytest.mark.parametrize('obj,class_or_tuple', [ - (1, int), - (1, (int,)), - (1, str | int), - (1, int | str | list), - (TestType(), TestType), - (None, types.NoneType), -]) + +@pytest.mark.parametrize( + 'obj,class_or_tuple', + [ + (1, int), + (1, (int,)), + (1, str | int), + (1, int | str | list), + (TestType(), TestType), + (None, types.NoneType), + ], +) def test_assert_that_is_instance(obj, class_or_tuple): assert_that_is_instance(obj, class_or_tuple) -@pytest.mark.parametrize('obj,class_or_tuple,expected_exception_msg', [ - ( - 1, - str, - 'expected \'str\', got \'int\'', - ), - ( - 1, - (str,), - 'expected \'str\', got \'int\'', - ), - ( - 1, - str | float, - 'expected either \'str\' or \'float\', got \'int\'', - ), - ( - 1, - str | float | list, - 'expected either \'str\', \'float\' or \'list\', got \'int\'', - ), - ( - 1, - TestType, - 'expected \'NOT TestType\', got \'int\'', - ), -]) + +@pytest.mark.parametrize( + 'obj,class_or_tuple,expected_exception_msg', + [ + ( + 1, + str, + "expected 'str', got 'int'", + ), + ( + 1, + (str,), + "expected 'str', got 'int'", + ), + ( + 1, + str | float, + "expected either 'str' or 'float', got 'int'", + ), + ( + 1, + str | float | list, + "expected either 'str', 'float' or 'list', got 'int'", + ), + ( + 1, + TestType, + "expected 'NOT TestType', got 'int'", + ), + ], +) def test_assert_that_is_instance_exceptions( obj, class_or_tuple, diff --git a/tests/unit/utils/test_get_relative_path_segments.py b/tests/unit/utils/test_get_relative_path_segments.py index 66ba580..c69fc9c 100644 --- a/tests/unit/utils/test_get_relative_path_segments.py +++ b/tests/unit/utils/test_get_relative_path_segments.py @@ -12,65 +12,68 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.utils import get_relative_path_segments -import pytest import pathlib -@pytest.mark.parametrize('path,root,expected', [ - (pathlib.Path('/'), pathlib.Path('/'), []), - (pathlib.Path('/a'), pathlib.Path('/'), ['a']), - (pathlib.Path('/a/'), pathlib.Path('/'), ['a']), - (pathlib.Path('/a'), pathlib.Path('/a'), []), - (pathlib.Path('/a/'), pathlib.Path('/a'), []), - (pathlib.Path('/a'), pathlib.Path('/a/'), []), - (pathlib.Path('/a/'), pathlib.Path('/a/'), []), - (pathlib.Path('/a/b'), pathlib.Path('/'), ['a', 'b']), - (pathlib.Path('/a/b/'), pathlib.Path('/'), ['a', 'b']), - (pathlib.Path('/a/b'), pathlib.Path('/a'), ['b']), - (pathlib.Path('/a/b/'), pathlib.Path('/a'), ['b']), - (pathlib.Path('/a/b'), pathlib.Path('/a/'), ['b']), - (pathlib.Path('/a/b/'), pathlib.Path('/a/'), ['b']), - (pathlib.Path('/a/b'), pathlib.Path('/a/b'), []), - (pathlib.Path('/a/b/'), pathlib.Path('/a/b'), []), - (pathlib.Path('/a/b'), pathlib.Path('/a/b/'), []), - (pathlib.Path('/a/b/'), pathlib.Path('/a/b/'), []), +import pytest - (pathlib.Path('./'), pathlib.Path('./'), []), - (pathlib.Path('./a'), pathlib.Path('./'), ['a']), - (pathlib.Path('./a/'), pathlib.Path('./'), ['a']), - (pathlib.Path('./a'), pathlib.Path('./a'), []), - (pathlib.Path('./a/'), pathlib.Path('./a'), []), - (pathlib.Path('./a'), pathlib.Path('./a/'), []), - (pathlib.Path('./a/'), pathlib.Path('./a/'), []), - (pathlib.Path('./a/b'), pathlib.Path('./'), ['a', 'b']), - (pathlib.Path('./a/b/'), pathlib.Path('./'), ['a', 'b']), - (pathlib.Path('./a/b'), pathlib.Path('./a'), ['b']), - (pathlib.Path('./a/b/'), pathlib.Path('./a'), ['b']), - (pathlib.Path('./a/b'), pathlib.Path('./a/'), ['b']), - (pathlib.Path('./a/b/'), pathlib.Path('./a/'), ['b']), - (pathlib.Path('./a/b'), pathlib.Path('./a/b'), []), - (pathlib.Path('./a/b/'), pathlib.Path('./a/b'), []), - (pathlib.Path('./a/b'), pathlib.Path('./a/b/'), []), - (pathlib.Path('./a/b/'), pathlib.Path('./a/b/'), []), +from src.jcloud_docsgen.utils import get_relative_path_segments - (pathlib.Path(''), pathlib.Path(''), []), - (pathlib.Path('a'), pathlib.Path(''), ['a']), - (pathlib.Path('a/'), pathlib.Path(''), ['a']), - (pathlib.Path('a'), pathlib.Path('a'), []), - (pathlib.Path('a/'), pathlib.Path('a'), []), - (pathlib.Path('a'), pathlib.Path('a/'), []), - (pathlib.Path('a/'), pathlib.Path('a/'), []), - (pathlib.Path('a/b'), pathlib.Path(''), ['a', 'b']), - (pathlib.Path('a/b/'), pathlib.Path(''), ['a', 'b']), - (pathlib.Path('a/b'), pathlib.Path('a'), ['b']), - (pathlib.Path('a/b/'), pathlib.Path('a'), ['b']), - (pathlib.Path('a/b'), pathlib.Path('a/'), ['b']), - (pathlib.Path('a/b/'), pathlib.Path('a/'), ['b']), - (pathlib.Path('a/b'), pathlib.Path('a/b'), []), - (pathlib.Path('a/b/'), pathlib.Path('a/b'), []), - (pathlib.Path('a/b'), pathlib.Path('a/b/'), []), - (pathlib.Path('a/b/'), pathlib.Path('a/b/'), []), -]) +@pytest.mark.parametrize( + 'path,root,expected', + [ + (pathlib.Path('/'), pathlib.Path('/'), []), + (pathlib.Path('/a'), pathlib.Path('/'), ['a']), + (pathlib.Path('/a/'), pathlib.Path('/'), ['a']), + (pathlib.Path('/a'), pathlib.Path('/a'), []), + (pathlib.Path('/a/'), pathlib.Path('/a'), []), + (pathlib.Path('/a'), pathlib.Path('/a/'), []), + (pathlib.Path('/a/'), pathlib.Path('/a/'), []), + (pathlib.Path('/a/b'), pathlib.Path('/'), ['a', 'b']), + (pathlib.Path('/a/b/'), pathlib.Path('/'), ['a', 'b']), + (pathlib.Path('/a/b'), pathlib.Path('/a'), ['b']), + (pathlib.Path('/a/b/'), pathlib.Path('/a'), ['b']), + (pathlib.Path('/a/b'), pathlib.Path('/a/'), ['b']), + (pathlib.Path('/a/b/'), pathlib.Path('/a/'), ['b']), + (pathlib.Path('/a/b'), pathlib.Path('/a/b'), []), + (pathlib.Path('/a/b/'), pathlib.Path('/a/b'), []), + (pathlib.Path('/a/b'), pathlib.Path('/a/b/'), []), + (pathlib.Path('/a/b/'), pathlib.Path('/a/b/'), []), + (pathlib.Path('./'), pathlib.Path('./'), []), + (pathlib.Path('./a'), pathlib.Path('./'), ['a']), + (pathlib.Path('./a/'), pathlib.Path('./'), ['a']), + (pathlib.Path('./a'), pathlib.Path('./a'), []), + (pathlib.Path('./a/'), pathlib.Path('./a'), []), + (pathlib.Path('./a'), pathlib.Path('./a/'), []), + (pathlib.Path('./a/'), pathlib.Path('./a/'), []), + (pathlib.Path('./a/b'), pathlib.Path('./'), ['a', 'b']), + (pathlib.Path('./a/b/'), pathlib.Path('./'), ['a', 'b']), + (pathlib.Path('./a/b'), pathlib.Path('./a'), ['b']), + (pathlib.Path('./a/b/'), pathlib.Path('./a'), ['b']), + (pathlib.Path('./a/b'), pathlib.Path('./a/'), ['b']), + (pathlib.Path('./a/b/'), pathlib.Path('./a/'), ['b']), + (pathlib.Path('./a/b'), pathlib.Path('./a/b'), []), + (pathlib.Path('./a/b/'), pathlib.Path('./a/b'), []), + (pathlib.Path('./a/b'), pathlib.Path('./a/b/'), []), + (pathlib.Path('./a/b/'), pathlib.Path('./a/b/'), []), + (pathlib.Path(''), pathlib.Path(''), []), + (pathlib.Path('a'), pathlib.Path(''), ['a']), + (pathlib.Path('a/'), pathlib.Path(''), ['a']), + (pathlib.Path('a'), pathlib.Path('a'), []), + (pathlib.Path('a/'), pathlib.Path('a'), []), + (pathlib.Path('a'), pathlib.Path('a/'), []), + (pathlib.Path('a/'), pathlib.Path('a/'), []), + (pathlib.Path('a/b'), pathlib.Path(''), ['a', 'b']), + (pathlib.Path('a/b/'), pathlib.Path(''), ['a', 'b']), + (pathlib.Path('a/b'), pathlib.Path('a'), ['b']), + (pathlib.Path('a/b/'), pathlib.Path('a'), ['b']), + (pathlib.Path('a/b'), pathlib.Path('a/'), ['b']), + (pathlib.Path('a/b/'), pathlib.Path('a/'), ['b']), + (pathlib.Path('a/b'), pathlib.Path('a/b'), []), + (pathlib.Path('a/b/'), pathlib.Path('a/b'), []), + (pathlib.Path('a/b'), pathlib.Path('a/b/'), []), + (pathlib.Path('a/b/'), pathlib.Path('a/b/'), []), + ], +) def test_get_relative_path_segments(path, root, expected): assert get_relative_path_segments(path, root) == expected diff --git a/tests/unit/utils/test_human_readable_list.py b/tests/unit/utils/test_human_readable_list.py index e2c921b..12f7f83 100644 --- a/tests/unit/utils/test_human_readable_list.py +++ b/tests/unit/utils/test_human_readable_list.py @@ -12,48 +12,53 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.utils import human_readable_list import pytest -@pytest.mark.parametrize('ls,final_separator,quotation_mark,expected', [ - ([], '', '', ''), - ([], 'and', '', ''), - ([], 'and', '\'', ''), - ([1], '', '', '1'), - ([-1], '', '', '-1'), - ([0], '', '', '0'), - ([0.0], '', '', '0.0'), - ([-0.0], '', '', '-0.0'), - ([4.2], '', '', '4.2'), - ([-4.2], '', '', '-4.2'), - (['a'], '', '', 'a'), - ([1], 'and', '', '1'), - (['a'], 'and', '', 'a'), - ([1], 'and', '\'', '\'1\''), - (['a'], 'and', '\'', '\'a\''), - ([1, 2], 'and', '', '1 and 2'), - ([1, 2], 'and', '\'', '\'1\' and \'2\''), - ([1, 'a'], 'and', '', '1 and a'), - ([1, 'a'], 'and', '\'', '\'1\' and \'a\''), - ([1, 'a'], 'and', '', '1 and a'), - ([1, 'a'], 'and', '\'', '\'1\' and \'a\''), - ([1, 'a'], 'and', '\'', '\'1\' and \'a\''), - ([1, 'a'], '', '', '1 a'), - ([1, 'a'], '', '\'', '\'1\' \'a\''), - ([1, 'a'], '', '', '1 a'), - ([1, 'a'], '', '\'', '\'1\' \'a\''), - ([1, 'a'], '', '\'', '\'1\' \'a\''), - ([1, 2, 3], 'and', '', '1, 2 and 3'), - ([1, 2, 3], '', '', '1, 2 3'), - ([1, 2, 3], 'and', '\'', '\'1\', \'2\' and \'3\''), - ([1, 2, 3], '', '\'', '\'1\', \'2\' \'3\''), - ([1, 2, 3, 42, 'a', 23], 'and', '', '1, 2, 3, 42, a and 23'), - ( - [1, 2, 3, 42, 'a', 23], - 'and', - '\'', - '\'1\', \'2\', \'3\', \'42\', \'a\' and \'23\'', - ), -]) +from src.jcloud_docsgen.utils import human_readable_list + + +@pytest.mark.parametrize( + 'ls,final_separator,quotation_mark,expected', + [ + ([], '', '', ''), + ([], 'and', '', ''), + ([], 'and', "'", ''), + ([1], '', '', '1'), + ([-1], '', '', '-1'), + ([0], '', '', '0'), + ([0.0], '', '', '0.0'), + ([-0.0], '', '', '-0.0'), + ([4.2], '', '', '4.2'), + ([-4.2], '', '', '-4.2'), + (['a'], '', '', 'a'), + ([1], 'and', '', '1'), + (['a'], 'and', '', 'a'), + ([1], 'and', "'", "'1'"), + (['a'], 'and', "'", "'a'"), + ([1, 2], 'and', '', '1 and 2'), + ([1, 2], 'and', "'", "'1' and '2'"), + ([1, 'a'], 'and', '', '1 and a'), + ([1, 'a'], 'and', "'", "'1' and 'a'"), + ([1, 'a'], 'and', '', '1 and a'), + ([1, 'a'], 'and', "'", "'1' and 'a'"), + ([1, 'a'], 'and', "'", "'1' and 'a'"), + ([1, 'a'], '', '', '1 a'), + ([1, 'a'], '', "'", "'1' 'a'"), + ([1, 'a'], '', '', '1 a'), + ([1, 'a'], '', "'", "'1' 'a'"), + ([1, 'a'], '', "'", "'1' 'a'"), + ([1, 2, 3], 'and', '', '1, 2 and 3'), + ([1, 2, 3], '', '', '1, 2 3'), + ([1, 2, 3], 'and', "'", "'1', '2' and '3'"), + ([1, 2, 3], '', "'", "'1', '2' '3'"), + ([1, 2, 3, 42, 'a', 23], 'and', '', '1, 2, 3, 42, a and 23'), + ( + [1, 2, 3, 42, 'a', 23], + 'and', + "'", + "'1', '2', '3', '42', 'a' and '23'", + ), + ], +) def test_human_readable_list(ls, final_separator, quotation_mark, expected): assert human_readable_list(ls, final_separator, quotation_mark) == expected diff --git a/tests/unit/utils/test_non_empty_str.py b/tests/unit/utils/test_non_empty_str.py index 0b57d31..2ce7b11 100644 --- a/tests/unit/utils/test_non_empty_str.py +++ b/tests/unit/utils/test_non_empty_str.py @@ -12,19 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -from src.jcloud_docsgen.utils import non_empty_str import pytest -@pytest.mark.parametrize('value,expected', [ - (None, None), - ('', None), - (' ', None), - (' ', None), - (' ', None), - (' a ', ' a '), - (' a', ' a'), - ('a ', 'a '), - ('a', 'a'), -]) +from src.jcloud_docsgen.utils import non_empty_str + + +@pytest.mark.parametrize( + 'value,expected', + [ + (None, None), + ('', None), + (' ', None), + (' ', None), + (' ', None), + (' a ', ' a '), + (' a', ' a'), + ('a ', 'a '), + ('a', 'a'), + ], +) def test_non_empty_str(value, expected): assert non_empty_str(value) == expected diff --git a/tests/utils/ast_node.py b/tests/utils/ast_node.py index 9beb441..22dd1fc 100644 --- a/tests/utils/ast_node.py +++ b/tests/utils/ast_node.py @@ -12,23 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union import ast -__all__ = [ - 'ast_node' -] +__all__ = ['ast_node'] -def ast_node(statement: str) -> Union[ast.stmt, None]: - ''' + +def ast_node(statement: str) -> ast.stmt | None: + """ Returns an AST node from the statement. :param statement: The statement. :type statement: str :return: The node. - :rtype: Union[ast.stmt, None] - ''' + :rtype: ast.stmt | None + """ body = ast.parse(statement).body if not body: