From 2211175062814652a664c1070bc4106211169baf 2025-03-02 12:52:32 From: Branko Majic Date: 2025-03-02 12:52:32 Subject: [PATCH] [mapping_generator.py] Added support for YAML output to info command: - The YAML output format for mappings should provide user with an easy way to get started with assigning the mappings in template. --- diff --git a/requirements.in b/requirements.in index 00a778ef7b8e25a9e2c0d7524b61aa4d024dbb4c..98c3f691f9494aeaacf1c52521e42b3df1a84c89 100644 --- a/requirements.in +++ b/requirements.in @@ -4,6 +4,9 @@ defusedxml ~= 0.7.0 # Command line option handling. Click ~= 8.1.0 +# mapping-generator +PyYAML ~= 6.0.0 + # Python script development. flake8 pip-tools diff --git a/requirements.txt b/requirements.txt index f72cd28819bacdde7128911a447db3e6e2d60c62..3041d69be326d4f619de174d9ede5ca667672465 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,8 @@ pyproject-hooks==1.2.0 # via # build # pip-tools +pyyaml==6.0.2 + # via -r requirements.in wheel==0.45.1 # via pip-tools diff --git a/utils/mapping_generator.py b/utils/mapping_generator.py index 42af18c6ac9871181181ec93b7dafcd4b7d984a6..df489032e7f5874e94ac50fcec2edccaefca3ac2 100755 --- a/utils/mapping_generator.py +++ b/utils/mapping_generator.py @@ -19,10 +19,63 @@ import shutil import math import click +import yaml from defusedxml import ElementTree +def display_mappables_as_text(mappables): + """ + Display mappables in text format. + + :param mappables: List of mappable IDs in the template. + :type mappable: list[str] + """ + + # Show mappables in multiple columns, while enforcing a minimum column height (element count). For example, if + # there are only 5 mappables, show them in a single column instead of splitting them up into multiple ones. + terminal_size = shutil.get_terminal_size((80, 20)) + column_spacing = 4 + row_threshold = math.floor(terminal_size.lines * 0.5) + column_width = max([len(m) for m in mappables]) + columns = math.floor((terminal_size.columns) / (column_width + column_spacing)) + page_threshold = row_threshold * columns + + # Expand the list with blank strings in order to have exact number of 'cells' when printing to + # screeen. Simplifies the code dealing with printing a bit and avoid invalid index access. + if len(mappables) <= row_threshold: + rows = len(mappables) + elif len(mappables) <= page_threshold: + rows = row_threshold + mappables.extend([''] * (page_threshold - len(mappables))) + else: + rows = math.ceil(len(mappables) / columns) + mappables.extend([''] * (columns * rows - len(mappables))) + + click.echo('Mappables:\n') + + for i in range(rows): + click.echo((" " * column_spacing).join([f'{m:<{column_width}}' for m in mappables[i::rows]])) + + +def display_mappables_as_yaml(mappables): + """ + Display mappables in YAML format. + + :param mappables: List of mappable IDs in the template. + :type mappable: list[str] + """ + + document = { + 'mappables': {} + } + + for mappable in mappables: + document['mappables'][mappable] = '' + + click.echo(yaml.dump(document, width=4096)) + + # Allow use of short option for showing help. CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) @@ -42,7 +95,8 @@ def cli(): @cli.command() @click.argument('template', type=click.File('r')) @click.option('--search', '-s', default='', help='only show matching mappings') -def info(template, search): +@click.option('--output-format', '-f', type=click.Choice(['text', 'yaml']), default='text', help='output format') +def info(template, search, output_format): """ Shows information about the passed-in SVG template. This currently includes: @@ -60,37 +114,27 @@ def info(template, search): ] matched_mappables = sorted([e.get('id') for e in mappable_elements if search in e.get('id')]) - if not mappable_elements: - click.echo('No mappables found in the specified template. Please check that you have specified correct file.') + if output_format == 'yaml': + click.echo('---\n') + if not mappable_elements: + error = 'No mappables found in the specified template. Please check that you have specified correct file.' elif not matched_mappables: - click.echo('Search term did not match any mappable in the specified template.') - + error = 'Search term did not match any mappable in the specified template.' else: - # Show mappables in multiple columns, while enforcing a minimum column height (element count). For example, if - # there are only 5 mappables, show them in a single column instead of splitting them up into multiple ones. - terminal_size = shutil.get_terminal_size((80, 20)) - column_spacing = 4 - row_threshold = math.floor(terminal_size.lines * 0.5) - column_width = max([len(m) for m in matched_mappables]) - columns = math.floor((terminal_size.columns) / (column_width + column_spacing)) - page_threshold = row_threshold * columns - - # Expand the list with blank strings in order to have exact number of 'cells' when printing to - # screeen. Simplifies the code dealing with printing a bit and avoid invalid index access. - if len(matched_mappables) <= row_threshold: - rows = len(matched_mappables) - elif len(matched_mappables) <= page_threshold: - rows = row_threshold - matched_mappables.extend([''] * (page_threshold - len(matched_mappables))) - else: - rows = math.ceil(len(matched_mappables) / columns) - matched_mappables.extend([''] * (columns * rows - len(matched_mappables))) - - click.echo('Mappables:\n') - - for i in range(rows): - click.echo((" " * column_spacing).join([f'{m:<{column_width}}' for m in matched_mappables[i::rows]])) + error = None + + if error and output_format == 'yaml': + error = yaml.dump({'error': error}, width=4096) + + if error: + click.echo(error) + + elif output_format == 'text': + display_mappables_as_text(matched_mappables) + + elif output_format == 'yaml': + display_mappables_as_yaml(matched_mappables) if __name__ == '__main__':