Skip to content

Commit f15c584

Browse files
authored
Merge pull request #11 from ModelCloud/codex/check-logbar-api-terminal-state-requirement
Allow LogBar to run without a terminal
2 parents 1eb74bf + f4bd8b6 commit f15c584

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

logbar/terminal.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# adapted from github.com/onsim/shutils
22
import os
3-
import sys
3+
import shutil
44

55

66
def terminal_size(fallback=(80, 24)):
@@ -11,8 +11,7 @@ def terminal_size(fallback=(80, 24)):
1111
the value is a positive integer, it is used.
1212
1313
When COLUMNS or LINES is not defined, which is the common case,
14-
the terminal connected to sys.__stdout__ is queried
15-
by invoking os.get_terminal_size.
14+
shutil.get_terminal_size is used to determine the current terminal size.
1615
1716
If the terminal size cannot be successfully queried, either because
1817
the system doesn't support querying, or because we are not
@@ -36,10 +35,11 @@ def terminal_size(fallback=(80, 24)):
3635
# only query if necessary
3736
if columns <= 0 or lines <= 0:
3837
try:
39-
size = os.get_terminal_size(sys.__stdout__.fileno())
40-
except (AttributeError, ValueError, OSError):
41-
# stdout is None, closed, detached, or not a terminal, or
42-
# os.get_terminal_size() is unsupported
38+
size = shutil.get_terminal_size(fallback)
39+
except (OSError, ValueError):
40+
# shutil.get_terminal_size failed because the runtime does not have an
41+
# attached terminal. Fall back to the provided default which mirrors
42+
# the behaviour of shutil.get_terminal_size when a fallback is supplied.
4343
size = os.terminal_size(fallback)
4444
if columns <= 0:
4545
columns = size.columns or fallback[0]

tests/test_log.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import io
2-
import unittest
32
from contextlib import redirect_stdout
3+
import unittest
4+
from unittest import mock
5+
46

57
from logbar import LogBar
68

@@ -29,6 +31,19 @@ def test_levels(self):
2931
log.error("hello error")
3032
log.critical("hello critical")
3133

34+
def test_log_without_terminal_state(self):
35+
"""LogBar should operate even when the runtime lacks a terminal."""
36+
37+
stdout = io.StringIO()
38+
39+
with mock.patch('sys.stdout', stdout), \
40+
mock.patch('logbar.terminal.shutil.get_terminal_size', side_effect=OSError()), \
41+
mock.patch.dict('logbar.terminal.os.environ', {}, clear=True):
42+
log.info("logging without terminal")
43+
44+
# The log output should have been written to the patched stdout buffer.
45+
self.assertIn("logging without terminal", stdout.getvalue())
46+
3247
def test_percent_formatting(self):
3348
output = self.capture_log(log.info, "%d", 123)
3449
self.assertIn("123", output)

tests/test_progress.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,16 @@ def test_draw_respects_terminal_width(self):
116116
rendered_line = output.lstrip('\r')
117117

118118
self.assertEqual(len(rendered_line), columns)
119+
120+
def test_draw_without_terminal_state(self):
121+
pb = log.pb(10).manual()
122+
pb.current_iter_step = 5
123+
124+
with patch('logbar.terminal.shutil.get_terminal_size', side_effect=OSError()), \
125+
patch.dict('logbar.terminal.os.environ', {}, clear=True):
126+
buffer = StringIO()
127+
with redirect_stdout(buffer):
128+
pb.draw()
129+
130+
output = buffer.getvalue()
131+
self.assertIn('[5/10]', output)

0 commit comments

Comments
 (0)