From 6ddbd17497c78ff4eb1b57fde695691bd400f6e8 Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Wed, 21 Oct 2026 12:59:18 +0200 Subject: [PATCH] refactor(utils)!: move markdown_table to utility module Moved the markdown_table utility function from the Python documentation generator core module to the utility module. The public exports definition of the utility module and all imports were updated. The test module was also moved to the appropriate new path and the testing functions were renamed. --- src/jcloud_docsgen/core/python/_core.py | 108 +----------------- src/jcloud_docsgen/utils.py | 103 +++++++++++++++++ .../test_markdown_table.py} | 10 +- 3 files changed, 111 insertions(+), 110 deletions(-) rename tests/unit/{core/python/_core/test__markdown_table.py => utils/test_markdown_table.py} (98%) diff --git a/src/jcloud_docsgen/core/python/_core.py b/src/jcloud_docsgen/core/python/_core.py index 483829a..a8a8025 100644 --- a/src/jcloud_docsgen/core/python/_core.py +++ b/src/jcloud_docsgen/core/python/_core.py @@ -28,7 +28,7 @@ from ...exceptions import ( InvalidNamespaceError, PythonArgumentStructureError, ) -from ...utils import fit_row_length, get_relative_path_segments, non_empty_str +from ...utils import get_relative_path_segments, markdown_table, non_empty_str from .arguments import PythonArgumentKind, PythonFunctionArgument from .definitions import ( PythonAsyncFunctionDefinition, @@ -184,108 +184,6 @@ def _signature_argument_list( return args -def _markdown_table( - header: tuple, - body: list[tuple], - *, - allow_markdown_table: bool = False, - force_row_lengths: bool = False, - one_line_values: bool = True, - missing_value: str = '--', -) -> str: - """ - Generates a table. - - If ``allow_markdown_table`` is ``False``, an alternative - representation is used. - - :param headers: The table headers. - :type headers: tuple - :param body: The table body. - :type body: list[tuple] - :param allow_markdown_table: Controls whether a markdown table may be - used. - :type allow_markdown_table: bool - :param force_row_lengths: Controls whether an exception is raised if - a row does not have the correct length. - :type force_row_lengths: bool - :param one_line_values: Controls whether all newlines in all values - are replaced with spaces. - :type one_line_values: bool - :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 '' - - header_len = len(header) - - if allow_markdown_table: - table = ( - '| ' + ' | '.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' - f'{"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', ' ') - .replace('|', '\\|') - if one_line_values - else str( - col if col is not None else missing_value - ).replace('|', '\\|') - for col in row - ] - ) - + ' |\n' - ) - else: - table = '' - - for row in body: - if len(row) != header_len: - if force_row_lengths: - raise ValueError( - f'expected {header_len} value' - f'{"s" if header_len > 1 else ""}, got {len(row)}' - ) - else: - row = fit_row_length(header_len, row) - - sep = '- ' - for i, col in enumerate(row): - table += ( - 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) - ) - + '\n\n' - ) - sep = ' ' - - return table.strip() - - def _is_docstring(docstring: str | PythonDocstring | None) -> bool: """ Checks whether the docstring is a docstring or an empty docstring. @@ -621,7 +519,7 @@ class PythonDefinitionDocumentationGenerator: ) if params_types: - md += _markdown_table( + md += markdown_table( ['Parameter', 'Type', 'Kind', 'Default value', 'Description'], [ ( @@ -700,7 +598,7 @@ class PythonDefinitionDocumentationGenerator: md += self.level * '#' + '# Exceptions\n\n' if self._docstring.raises: - md += _markdown_table( + md += markdown_table( ('Exception', 'Description'), [ ( diff --git a/src/jcloud_docsgen/utils.py b/src/jcloud_docsgen/utils.py index 4c355b7..d11665e 100644 --- a/src/jcloud_docsgen/utils.py +++ b/src/jcloud_docsgen/utils.py @@ -35,6 +35,7 @@ __all__ = [ 'non_empty_str', 'get_relative_path_segments', 'fit_row_length', + 'markdown_table', ] @@ -260,3 +261,105 @@ def fit_row_length(expected: int, row: tuple) -> tuple: return row[:expected] else: return row + (None,) * (expected - len(row)) + + +def markdown_table( + header: tuple, + body: list[tuple], + *, + allow_markdown_table: bool = False, + force_row_lengths: bool = False, + one_line_values: bool = True, + missing_value: str = '--', +) -> str: + """ + Generates a table. + + If ``allow_markdown_table`` is ``False``, an alternative + representation is used. + + :param headers: The table headers. + :type headers: tuple + :param body: The table body. + :type body: list[tuple] + :param allow_markdown_table: Controls whether a markdown table may be + used. + :type allow_markdown_table: bool + :param force_row_lengths: Controls whether an exception is raised if + a row does not have the correct length. + :type force_row_lengths: bool + :param one_line_values: Controls whether all newlines in all values + are replaced with spaces. + :type one_line_values: bool + :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 '' + + header_len = len(header) + + if allow_markdown_table: + table = ( + '| ' + ' | '.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' + f'{"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', ' ') + .replace('|', '\\|') + if one_line_values + else str( + col if col is not None else missing_value + ).replace('|', '\\|') + for col in row + ] + ) + + ' |\n' + ) + else: + table = '' + + for row in body: + if len(row) != header_len: + if force_row_lengths: + raise ValueError( + f'expected {header_len} value' + f'{"s" if header_len > 1 else ""}, got {len(row)}' + ) + else: + row = fit_row_length(header_len, row) + + sep = '- ' + for i, col in enumerate(row): + table += ( + 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) + ) + + '\n\n' + ) + sep = ' ' + + return table.strip() diff --git a/tests/unit/core/python/_core/test__markdown_table.py b/tests/unit/utils/test_markdown_table.py similarity index 98% rename from tests/unit/core/python/_core/test__markdown_table.py rename to tests/unit/utils/test_markdown_table.py index 4ec8e68..08dddce 100644 --- a/tests/unit/core/python/_core/test__markdown_table.py +++ b/tests/unit/utils/test_markdown_table.py @@ -14,7 +14,7 @@ import pytest -from src.jcloud_docsgen.core.python._core import _markdown_table +from src.jcloud_docsgen.utils import markdown_table @pytest.mark.parametrize( @@ -318,7 +318,7 @@ from src.jcloud_docsgen.core.python._core import _markdown_table ), ], ) -def test__markdown_table( +def test_markdown_table( header, body, allow_markdown_table, @@ -328,7 +328,7 @@ def test__markdown_table( expected, ): assert ( - _markdown_table( + markdown_table( header, body, allow_markdown_table=allow_markdown_table, @@ -468,7 +468,7 @@ def test__markdown_table( ), ], ) -def test__markdown_table_exceptions( +def test_markdown_table_exceptions( header, body, allow_markdown_table, @@ -479,7 +479,7 @@ def test__markdown_table_exceptions( expected_exception_msg, ): with pytest.raises(expected_exception) as exc_info: - _markdown_table( + markdown_table( header, body, allow_markdown_table=allow_markdown_table,