Changeset - 221117506281
[Not reviewed]
0 3 0
Branko Majic (branko) - 1 month ago 2025-03-02 12:52:32
branko@majic.rs
[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.
3 files changed with 78 insertions and 29 deletions:
0 comments (0 inline, 0 general) First comment
requirements.in
Show inline comments
 
@@ -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
requirements.txt
Show inline comments
 
@@ -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
 

	
utils/mapping_generator.py
Show inline comments
 
@@ -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__':
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now