Skip to content

Commit 8a0687a

Browse files
fix: support TerminalReporter.isatty being called
Fixes #13461.
1 parent b6e8144 commit 8a0687a

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

changelog/13461.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Corrected ``_pytest.terminal.TerminalReporter.isatty`` to support
2+
being called as a method. Before it was just a boolean which could
3+
break correct code when using ``-o log_cli=true``).

src/_pytest/terminal.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,9 @@ def __init__(self, config: Config, file: TextIO | None = None) -> None:
387387
self.reportchars = getreportopt(config)
388388
self.foldskipped = config.option.fold_skipped
389389
self.hasmarkup = self._tw.hasmarkup
390-
self.isatty = file.isatty()
390+
# isatty should be a method but was wrongly implemented as a boolean.
391+
# We use _CallableBool here to support both.
392+
self.isatty = _CallableBool(file.isatty())
391393
self._progress_nodeids_reported: set[str] = set()
392394
self._timing_nodeids_reported: set[str] = set()
393395
self._show_progress_info = self._determine_show_progress_info()
@@ -766,7 +768,7 @@ def _width_of_current_line(self) -> int:
766768
return self._tw.width_of_current_line
767769

768770
def pytest_collection(self) -> None:
769-
if self.isatty:
771+
if self.isatty():
770772
if self.config.option.verbose >= 0:
771773
self.write("collecting ... ", flush=True, bold=True)
772774
elif self.config.option.verbose >= 1:
@@ -779,7 +781,7 @@ def pytest_collectreport(self, report: CollectReport) -> None:
779781
self._add_stats("skipped", [report])
780782
items = [x for x in report.result if isinstance(x, Item)]
781783
self._numcollected += len(items)
782-
if self.isatty:
784+
if self.isatty():
783785
self.report_collect()
784786

785787
def report_collect(self, final: bool = False) -> None:
@@ -811,7 +813,7 @@ def report_collect(self, final: bool = False) -> None:
811813
line += f" / {skipped} skipped"
812814
if self._numcollected > selected:
813815
line += f" / {selected} selected"
814-
if self.isatty:
816+
if self.isatty():
815817
self.rewrite(line, bold=True, erase=True)
816818
if final:
817819
self.write("\n")
@@ -1636,3 +1638,14 @@ def _get_raw_skip_reason(report: TestReport) -> str:
16361638
elif reason == "Skipped":
16371639
reason = ""
16381640
return reason
1641+
1642+
1643+
class _CallableBool:
1644+
def __init__(self, value: bool):
1645+
self._value = value
1646+
1647+
def __bool__(self):
1648+
return self._value
1649+
1650+
def __call__(self):
1651+
return self._value

testing/test_terminal.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,16 @@ def test_long_xfail():
442442
]
443443
)
444444

445+
@pytest.mark.parametrize("isatty", [True, False])
446+
def test_isatty(self, pytester: Pytester, monkeypatch, isatty: bool) -> None:
447+
config = pytester.parseconfig()
448+
f = StringIO()
449+
monkeypatch.setattr(f, "isatty", lambda: isatty)
450+
tr = TerminalReporter(config, f)
451+
assert tr.isatty() == isatty
452+
# It was incorrectly implemented as a boolean so we still support using it as one.
453+
assert bool(tr.isatty) == isatty
454+
445455

446456
class TestCollectonly:
447457
def test_collectonly_basic(self, pytester: Pytester) -> None:

0 commit comments

Comments
 (0)