Removing helper functions providing Python < 3.3 compatibility

Functions used for deriving terminal width are no longer
necessary, as Python 3.3 introduced[0] built in solution.

Remaining helper function `utils.terminal_width` received docstring
explaining return parameters.

Method `_assign_max_widths` of the `TableFormatter` class was refactored
to no longer use the `stdout` argument. Uses of the method were adjusted accordingly.
Method now also has minimal docstring. Minor adjustment was made to inline comments
to more closely reflect functionality of the code.

[0]https://docs.python.org/3.8/library/os.html?highlight=get_terminal_size#os.get_terminal_size

Signed-off-by: Jiri Podivin <jpodivin@redhat.com>
Change-Id: I2898f099227e8c97aef6492c60f2f99038aa1357
This commit is contained in:
Jiri Podivin 2022-10-26 14:02:07 +02:00
parent fb9a3a9b2d
commit 72e81d7d84
3 changed files with 20 additions and 68 deletions

View File

@ -100,7 +100,7 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
# preference to wrapping columns smaller than 8 characters.
min_width = 8
self._assign_max_widths(
stdout, x, int(parsed_args.max_width), min_width,
x, int(parsed_args.max_width), min_width,
parsed_args.fit_width)
formatted = x.get_string()
@ -125,7 +125,7 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
# the Field column readable.
min_width = 16
self._assign_max_widths(
stdout, x, int(parsed_args.max_width), min_width,
x, int(parsed_args.max_width), min_width,
parsed_args.fit_width)
formatted = x.get_string()
@ -170,14 +170,18 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
return shrink_fields, shrink_remaining
@staticmethod
def _assign_max_widths(stdout, x, max_width, min_width=0, fit_width=False):
def _assign_max_widths(x, max_width, min_width=0, fit_width=False):
"""Set maximum widths for columns of table `x`,
with the last column recieving either leftover columns
or `min_width`, depending on what offers more space.
"""
if max_width > 0:
term_width = max_width
elif not fit_width:
# Fitting is disabled
return
else:
term_width = utils.terminal_width(stdout)
term_width = utils.terminal_width()
if not term_width:
# not a tty, so do not set any max widths
return
@ -204,6 +208,6 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
x.max_width[field] = max(min_width, shrink_to)
shrink_remaining -= shrink_to
# give the last shrinkable column shrink_to plus any remaining
# give the last shrinkable column any remaining shrink or min_width
field = shrink_fields[-1]
x.max_width[field] = max(min_width, shrink_remaining)

View File

@ -13,7 +13,6 @@
# under the License.
import os
import sys
from unittest import mock
from cliff.tests import base
@ -23,7 +22,7 @@ from cliff import utils
class TestTerminalWidth(base.TestBase):
def test(self):
width = utils.terminal_width(sys.stdout)
width = utils.terminal_width()
# Results are specific to the execution environment, so only assert
# that no error is raised.
if width is not None:
@ -33,8 +32,8 @@ class TestTerminalWidth(base.TestBase):
def test_get_terminal_size(self, mock_os):
ts = os.terminal_size((10, 5))
mock_os.get_terminal_size.return_value = ts
width = utils.terminal_width(sys.stdout)
width = utils.terminal_width()
self.assertEqual(10, width)
mock_os.get_terminal_size.side_effect = OSError()
width = utils.terminal_width(sys.stdout)
width = utils.terminal_width()
self.assertIs(None, width)

View File

@ -11,10 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import ctypes
import os
import struct
import sys
# Each edit operation is assigned different cost, such as:
# 'w' means swap operation, the cost is 0;
@ -93,63 +90,15 @@ def damerau_levenshtein(s1, s2, cost):
return row1[-1]
def terminal_width(stdout):
if hasattr(os, 'get_terminal_size'):
# python 3.3 onwards has built-in support for getting terminal size
try:
return os.get_terminal_size().columns
except OSError:
return None
def terminal_width():
"""Return terminal width in columns
if sys.platform == 'win32':
return _get_terminal_width_windows(stdout)
else:
return _get_terminal_width_ioctl(stdout)
def _get_terminal_width_windows(stdout):
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
std_to_win_handle = {
sys.stdin: STD_INPUT_HANDLE,
sys.stdout: STD_OUTPUT_HANDLE,
sys.stderr: STD_ERROR_HANDLE}
std_handle = std_to_win_handle.get(stdout)
if not std_handle:
return None
handle = ctypes.windll.kernel32.GetStdHandle(std_handle)
csbi = ctypes.create_string_buffer(22)
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(handle, csbi)
if res:
(size_x, size_y, cur_pos_x, cur_pos_y, attr,
left, top, right, bottom, max_size_x, max_size_y) = struct.unpack(
"hhhhHhhhhhh", csbi.raw)
return size_x
def _get_terminal_width_ioctl(stdout):
from fcntl import ioctl
import termios
Uses `os.get_terminal_size` function
:returns: terminal width
:rtype: int or None
"""
try:
# winsize structure has 4 unsigned short fields
winsize = b'\0' * struct.calcsize('hhhh')
try:
winsize = ioctl(stdout, termios.TIOCGWINSZ, winsize)
except IOError:
return None
except TypeError:
# this is raised in unit tests as stdout is sometimes a StringIO
return None
winsize = struct.unpack('hhhh', winsize)
columns = winsize[1]
if not columns:
return None
return columns
except IOError:
return os.get_terminal_size().columns
except OSError:
return None