Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added globus auth scope show command #1077

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Prev Previous commit
Next Next commit
Added TerminalTextWrapper
derek-globus committed Feb 5, 2025
commit ecf9df7ab0da0f30efc4e2f9574ae87a470d1582
22 changes: 3 additions & 19 deletions src/globus_cli/termio/printers/record_printer.py
Original file line number Diff line number Diff line change
@@ -2,14 +2,13 @@

import functools
import typing as t
from textwrap import TextWrapper

import click
import globus_sdk

from globus_cli.types import JsonValue

from ..terminal_info import TERM_INFO
from ..terminal_info import TerminalTextWrapper
from .base import Printer

if t.TYPE_CHECKING:
@@ -43,13 +42,11 @@ def __init__(
content_width: int | None = None,
) -> None:
self._fields = list(fields)
self._is_max_content_width_explicit = content_width is not None
self._base_item_wrapper = TextWrapper(
self._item_wrapper = TerminalTextWrapper(
initial_indent=" " * self._key_len,
subsequent_indent=" " * self._key_len,
width=content_width,
)
if content_width is not None:
self._base_item_wrapper.width = content_width

def echo(self, data: DataObject, stream: t.IO[str] | None = None) -> None:
for field in self._fields:
@@ -97,19 +94,6 @@ def _key_len(self) -> int:
"""The number of chars in the key column."""
return max(len(f.name) for f in self._fields) + 2

@property
def _item_wrapper(self) -> TextWrapper:
"""
Access the printers TextWrapper, modifying the width if necessary.

:returns: a TextWrapper instance for wrapping item values.
"""
# If the class was instantiated with an explicit max_content_width, don't
# override it.
if not self._is_max_content_width_explicit:
self._base_item_wrapper.width = TERM_INFO.columns
return self._base_item_wrapper


class RecordListPrinter(Printer[t.Iterable[DataObject]]):
"""
32 changes: 28 additions & 4 deletions src/globus_cli/termio/terminal_info.py
Original file line number Diff line number Diff line change
@@ -5,11 +5,14 @@
To do this effectively, they need to know where exactly to start wrapping text.
"""

from __future__ import annotations

import contextlib
import shutil
import typing as t
from textwrap import TextWrapper

__all__ = ("TERM_INFO",)
__all__ = ("TERM_INFO", "TerminalTextWrapper")


class VirtualTerminalInfo:
@@ -26,15 +29,36 @@ def indented(self, size: int) -> t.Iterator[None]:
"""
Context manager to temporarily decrease the available width for text wrapping.
"""

self._column_delta -= size
yield
self._column_delta += size
try:
yield
finally:
self._column_delta += size

@property
def columns(self) -> int:
computed_columns = self._base_columns + self._column_delta
return max(self.MIN_COLUMNS, computed_columns)


class TerminalTextWrapper(TextWrapper):
"""
A text wrapper customized for wrapping text to the terminal.

If width is not supplied, it will be evaluated from ``TERM_INFO``.
"""

def __init__(self, *args: t.Any, width: int | None = None, **kwargs: t.Any) -> None:
super().__init__(*args, **kwargs)
self._width = width

@property
def width(self) -> int:
return self._width or TERM_INFO.columns

@width.setter
def width(self, value: int) -> None:
self._width = value


TERM_INFO = VirtualTerminalInfo()
38 changes: 37 additions & 1 deletion tests/unit/termio/test_terminal_info.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from globus_cli.termio.terminal_info import VirtualTerminalInfo
from globus_cli.termio.terminal_info import (
TERM_INFO,
TerminalTextWrapper,
VirtualTerminalInfo,
)


def test_terminal_info_indents():
@@ -11,3 +15,35 @@ def test_terminal_info_indents():
assert term_info.columns == columns - 8
assert term_info.columns == columns - 4
assert term_info.columns == columns


def test_terminal_info_indentation_is_reset_on_exception():
term_info = VirtualTerminalInfo()

columns = term_info.columns
try:
with term_info.indented(4):
assert term_info.columns == columns - 4
raise ValueError("test")
except ValueError:
pass
assert term_info.columns == columns


def test_terminal_text_wrapper_wraps_to_terminal():
wrapper = TerminalTextWrapper()
assert wrapper.width == TERM_INFO.columns

a_line = "a" * wrapper.width
assert wrapper.wrap(a_line) == [a_line]
assert wrapper.wrap(a_line + "a") == [a_line, "a"]


def test_terminal_text_wrapper_respects_indentation():
wrapper = TerminalTextWrapper()

initial_width = TERM_INFO.columns
assert wrapper.width == initial_width

with TERM_INFO.indented(4):
assert wrapper.width == initial_width - 4
2 changes: 1 addition & 1 deletion tests/unit/termio/test_termio.py
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ def test_format_record_with_text_wrapping(capsys, monkeypatch):
monkeypatch.setattr("shutil.get_terminal_size", lambda *_, **__: fake_dimensions)
# Generate a new virtual terminal info object to recompute the columns
monkeypatch.setattr(
"globus_cli.termio.printers.record_printer.TERM_INFO",
"globus_cli.termio.terminal_info.TERM_INFO",
VirtualTerminalInfo(),
)
expected_width = int(0.8 * 120)