From ed73cfbd95b9222c57950ff727397e251ebca247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB=20=D0=96=D1=83=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2?= <33721692+LeaveMyYard@users.noreply.github.com> Date: Fri, 26 May 2023 23:02:47 +0300 Subject: Refactor Formatters, use functional approach --- robusta_krr/formatters/__init__.py | 8 +- robusta_krr/formatters/json.py | 22 +---- robusta_krr/formatters/pprint.py | 22 +---- robusta_krr/formatters/table.py | 171 ++++++++++++++++++------------------- robusta_krr/formatters/yaml.py | 23 ++--- 5 files changed, 100 insertions(+), 146 deletions(-) (limited to 'robusta_krr/formatters') diff --git a/robusta_krr/formatters/__init__.py b/robusta_krr/formatters/__init__.py index 0fc1c80..325cf01 100644 --- a/robusta_krr/formatters/__init__.py +++ b/robusta_krr/formatters/__init__.py @@ -1,4 +1,4 @@ -from .json import JSONFormatter -from .pprint import PPrintFormatter -from .table import TableFormatter -from .yaml import YAMLFormatter +from .json import json +from .pprint import pprint +from .table import table +from .yaml import yaml diff --git a/robusta_krr/formatters/json.py b/robusta_krr/formatters/json.py index 2c3a51e..c391da2 100644 --- a/robusta_krr/formatters/json.py +++ b/robusta_krr/formatters/json.py @@ -1,21 +1,7 @@ -from __future__ import annotations - -from robusta_krr.core.abstract.formatters import BaseFormatter +from robusta_krr.core.abstract import formatters from robusta_krr.core.models.result import Result -class JSONFormatter(BaseFormatter): - """Formatter for JSON output.""" - - __display_name__ = "json" - - def format(self, result: Result) -> str: - """Format the result as JSON. - - :param result: The results to format. - :type result: :class:`core.result.Result` - :returns: The formatted results. - :rtype: str - """ - - return result.json(indent=2) +@formatters.register() +def json(result: Result) -> str: + return result.json(indent=2) diff --git a/robusta_krr/formatters/pprint.py b/robusta_krr/formatters/pprint.py index bdfcc4c..9be637c 100644 --- a/robusta_krr/formatters/pprint.py +++ b/robusta_krr/formatters/pprint.py @@ -1,23 +1,9 @@ -from __future__ import annotations - from pprint import pformat -from robusta_krr.core.abstract.formatters import BaseFormatter +from robusta_krr.core.abstract import formatters from robusta_krr.core.models.result import Result -class PPrintFormatter(BaseFormatter): - """Formatter for object output with python's pprint module.""" - - __display_name__ = "pprint" - - def format(self, result: Result) -> str: - """Format the result using pprint.pformat(...) - - :param result: The results to format. - :type result: :class:`core.result.Result` - :returns: The formatted results. - :rtype: str - """ - - return pformat(result.dict()) +@formatters.register() +def pprint(result: Result) -> str: + return pformat(result.dict()) diff --git a/robusta_krr/formatters/table.py b/robusta_krr/formatters/table.py index 8ef1696..9776d80 100644 --- a/robusta_krr/formatters/table.py +++ b/robusta_krr/formatters/table.py @@ -1,10 +1,8 @@ -from __future__ import annotations - import itertools from rich.table import Table -from robusta_krr.core.abstract.formatters import BaseFormatter +from robusta_krr.core.abstract import formatters from robusta_krr.core.models.allocations import RecommendationValue from robusta_krr.core.models.result import ResourceScan, ResourceType, Result from robusta_krr.utils import resource_units @@ -13,88 +11,85 @@ NONE_LITERAL = "unset" NAN_LITERAL = "?" -class TableFormatter(BaseFormatter): - """Formatter for text output.""" - - __display_name__ = "table" - __rich_console__ = True - - def _format(self, value: RecommendationValue) -> str: - if value is None: - return NONE_LITERAL - elif isinstance(value, str): - return NAN_LITERAL - else: - return resource_units.format(value) - - def _format_request_str(self, item: ResourceScan, resource: ResourceType, selector: str) -> str: - allocated = getattr(item.object.allocations, selector)[resource] - recommended = getattr(item.recommended, selector)[resource] - severity = recommended.severity - - return ( - f"[{severity.color}]" - + self._format(allocated) - + " -> " - + self._format(recommended.value) - + f"[/{severity.color}]" - ) - - def format(self, result: Result) -> Table: - """Format the result as text. - - :param result: The result to format. - :type result: :class:`core.result.Result` - :returns: The formatted results. - :rtype: str - """ - - table = Table( - show_header=True, - header_style="bold magenta", - title=f"\n{result.description}\n" if result.description else None, - title_justify="left", - title_style="", - # TODO: Fix points calculation at [MAIN-270] - # caption=f"Scan result ({result.score} points)", - ) - - table.add_column("Number", justify="right", no_wrap=True) - table.add_column("Cluster", style="cyan") - table.add_column("Namespace", style="cyan") - table.add_column("Name", style="cyan") - table.add_column("Pods", style="cyan") - table.add_column("Old Pods", style="cyan") - table.add_column("Type", style="cyan") - table.add_column("Container", style="cyan") - for resource in ResourceType: - table.add_column(f"{resource.name} Requests") - table.add_column(f"{resource.name} Limits") - - for _, group in itertools.groupby( - enumerate(result.scans), key=lambda x: (x[1].object.cluster, x[1].object.namespace, x[1].object.name) - ): - group_items = list(group) - - for j, (i, item) in enumerate(group_items): - last_row = j == len(group_items) - 1 - full_info_row = j == 0 - - table.add_row( - f"[{item.severity.color}]{i + 1}.[/{item.severity.color}]", - item.object.cluster if full_info_row else "", - item.object.namespace if full_info_row else "", - item.object.name if full_info_row else "", - f"{item.object.current_pods_count}" if full_info_row else "", - f"{item.object.deleted_pods_count}" if full_info_row else "", - item.object.kind if full_info_row else "", - item.object.container, - *[ - self._format_request_str(item, resource, selector) - for resource in ResourceType - for selector in ["requests", "limits"] - ], - end_section=last_row, - ) - - return table +def _format(value: RecommendationValue) -> str: + if value is None: + return NONE_LITERAL + elif isinstance(value, str): + return NAN_LITERAL + else: + return resource_units.format(value) + + +def _format_request_str(item: ResourceScan, resource: ResourceType, selector: str) -> str: + allocated = getattr(item.object.allocations, selector)[resource] + recommended = getattr(item.recommended, selector)[resource] + severity = recommended.severity + + return ( + f"[{severity.color}]" + + _format(allocated) + + " -> " + + _format(recommended.value) + + f"[/{severity.color}]" + ) + + +@formatters.register(rich_console=True) +def table(result: Result) -> Table: + """Format the result as text. + + :param result: The result to format. + :type result: :class:`core.result.Result` + :returns: The formatted results. + :rtype: str + """ + + table = Table( + show_header=True, + header_style="bold magenta", + title=f"\n{result.description}\n" if result.description else None, + title_justify="left", + title_style="", + # TODO: Fix points calculation at [MAIN-270] + # caption=f"Scan result ({result.score} points)", + ) + + table.add_column("Number", justify="right", no_wrap=True) + table.add_column("Cluster", style="cyan") + table.add_column("Namespace", style="cyan") + table.add_column("Name", style="cyan") + table.add_column("Pods", style="cyan") + table.add_column("Old Pods", style="cyan") + table.add_column("Type", style="cyan") + table.add_column("Container", style="cyan") + for resource in ResourceType: + table.add_column(f"{resource.name} Requests") + table.add_column(f"{resource.name} Limits") + + for _, group in itertools.groupby( + enumerate(result.scans), key=lambda x: (x[1].object.cluster, x[1].object.namespace, x[1].object.name) + ): + group_items = list(group) + + for j, (i, item) in enumerate(group_items): + last_row = j == len(group_items) - 1 + full_info_row = j == 0 + + table.add_row( + f"[{item.severity.color}]{i + 1}.[/{item.severity.color}]", + item.object.cluster if full_info_row else "", + item.object.namespace if full_info_row else "", + item.object.name if full_info_row else "", + f"{item.object.current_pods_count}" if full_info_row else "", + f"{item.object.deleted_pods_count}" if full_info_row else "", + item.object.kind if full_info_row else "", + item.object.container, + *[ + _format_request_str(item, resource, selector) + for resource in ResourceType + for selector in ["requests", "limits"] + ], + end_section=last_row, + ) + + return table diff --git a/robusta_krr/formatters/yaml.py b/robusta_krr/formatters/yaml.py index c494bc1..37a030c 100644 --- a/robusta_krr/formatters/yaml.py +++ b/robusta_krr/formatters/yaml.py @@ -1,24 +1,11 @@ -from __future__ import annotations - import json -import yaml +import yaml as yaml_module -from robusta_krr.core.abstract.formatters import BaseFormatter +from robusta_krr.core.abstract import formatters from robusta_krr.core.models.result import Result -class YAMLFormatter(BaseFormatter): - """Formatter for YAML output.""" - - __display_name__ = "yaml" - - def format(self, result: Result) -> str: - """Format the result as YAML. - - :param result: The results to format. - :type result: :class:`core.result.Result` - :returns: The formatted results. - :rtype: str - """ - return yaml.dump(json.loads(result.json()), sort_keys=False) +@formatters.register() +def yaml(result: Result) -> str: + return yaml_module.dump(json.loads(result.json()), sort_keys=False) -- cgit v1.2.3