Skip to content

Commit

Permalink
cli: add indented Block classes
Browse files Browse the repository at this point in the history
Indented Blocks standardize indentation through the CLI, and Suggestion
Blocks take the suggestion configuration into consideration.

Signed-off-by: Renan Rodrigo <[email protected]>
  • Loading branch information
renanrodrigo committed Sep 26, 2024
1 parent b15e724 commit 39b13da
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 2 deletions.
55 changes: 54 additions & 1 deletion uaclient/cli/formatter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os
import re
import sys
from typing import List, Optional
import textwrap
from typing import Any, List, Optional

from uaclient.config import UAConfig
from uaclient.messages import TxtColor
Expand Down Expand Up @@ -182,3 +183,55 @@ def _fill_row(self, row: List[str]) -> str:
output += self.ljust(row[i], self.column_sizes[i]) + self.SEPARATOR
output += row[-1]
return output


class Block:
INDENT_SIZE = 4
INDENT_CHAR = " "

def __init__(
self,
title: Optional[str] = None,
content: Optional[List[Any]] = None,
):
self.title = title
self.content = content if content is not None else []

def __str__(self) -> str:
return self.to_string()

def to_string(self, line_length: Optional[int] = None) -> str:
if line_length is None:
line_length = _get_default_length()

line_length -= self.INDENT_SIZE

output = ""

if self.title:
output += (
TxtColor.BOLD
+ TxtColor.DISABLEGREY
+ self.title
+ TxtColor.ENDC
+ "\n"
)

for item in self.content:
if isinstance(item, (Block, Table)):
item_str = item.to_string(line_length=line_length)
else:
item_str = "\n".join(wrap_text(str(item), line_length)) + "\n"

output += textwrap.indent(
item_str, self.INDENT_CHAR * self.INDENT_SIZE
)

return output


class SuggestionBlock(Block):
def to_string(self, line_length: Optional[int] = None) -> str:
if ProOutputFormatterConfig.show_suggestions:
return super().to_string(line_length)
return ""
98 changes: 97 additions & 1 deletion uaclient/cli/tests/test_cli_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
import mock
import pytest

from uaclient.cli.formatter import Block
from uaclient.cli.formatter import ProOutputFormatterConfig as POFC
from uaclient.cli.formatter import Table, len_no_color, wrap_text
from uaclient.cli.formatter import (
SuggestionBlock,
Table,
len_no_color,
wrap_text,
)

M_PATH = "uaclient.cli.formatter."

Expand Down Expand Up @@ -269,3 +275,93 @@ def test_to_string_no_wrap_if_no_tty(self, _m_terminal_size, _m_is_tty):
c fg hijkl m
""" # noqa: E501
)


class TestBlock:
@mock.patch(M_PATH + "sys.stdout.isatty", return_value=False)
@mock.patch(
M_PATH + "os.get_terminal_size",
side_effect=OSError(),
)
def test_indents_and_wraps_content_when_len_specified(
self, _m_terminal_size, _m_is_tty
):
block = Block(
title="Example Title",
content=[
"Smaller content line",
"A slightly bigger line which needs to be wrapped to fit the screen", # noqa: E501
Block(
title="Inner block",
content=[
"Another small content line",
"Another slightly bigger line which needs to be wrapped to fit the screen", # noqa: E501
],
),
Table(
rows=[
[
"1",
"Table bigger last column which needs to be wrapped to fit the screen", # noqa: E501
],
[
"2",
"Table bigger last column which needs to be wrapped to fit the screen", # noqa: E501
],
[
"3",
"Table bigger last column which needs to be wrapped to fit the screen", # noqa: E501
],
]
),
],
)
assert block.to_string() == textwrap.dedent(
"""\
\x1b[1m\x1b[37mExample Title\x1b[0m
Smaller content line
A slightly bigger line which needs to be wrapped to fit the screen
\x1b[1m\x1b[37mInner block\x1b[0m
Another small content line
Another slightly bigger line which needs to be wrapped to fit the screen
1 Table bigger last column which needs to be wrapped to fit the screen
2 Table bigger last column which needs to be wrapped to fit the screen
3 Table bigger last column which needs to be wrapped to fit the screen
""" # noqa: E501
)
assert block.to_string(line_length=40) == textwrap.dedent(
"""\
\x1b[1m\x1b[37mExample Title\x1b[0m
Smaller content line
A slightly bigger line which needs
to be wrapped to fit the screen
\x1b[1m\x1b[37mInner block\x1b[0m
Another small content line
Another slightly bigger line
which needs to be wrapped to fit
the screen
1 Table bigger last column which
needs to be wrapped to fit the
screen
2 Table bigger last column which
needs to be wrapped to fit the
screen
3 Table bigger last column which
needs to be wrapped to fit the
screen
"""
)

def test_suggestions_can_be_disabled(self, FakeConfig):
suggestion_block = SuggestionBlock(
title="Suggestion", content=["Some content"]
)
POFC.init(FakeConfig())
assert suggestion_block.to_string() == textwrap.dedent(
"""\
\x1b[1m\x1b[37mSuggestion\x1b[0m
Some content
"""
)
POFC.disable_suggestions()
assert suggestion_block.to_string() == ""

0 comments on commit 39b13da

Please sign in to comment.