Skip to content

Commit 9c9bef2

Browse files
committed
terminal: disable OSC 9;4; terminal progress by default, except on Windows
Fix #13896.
1 parent bbb0c07 commit 9c9bef2

File tree

6 files changed

+60
-26
lines changed

6 files changed

+60
-26
lines changed

changelog/13896.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The terminal progress feature added in pytest 9.0.0 has been disabled by default, except on Windows, due to compatibility issues with some terminal emulators.
2+
3+
You may enable it again by passing ``-p terminalprogress``. We may enable it by default again once compatibility improves in the future.

doc/en/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ New features
178178

179179

180180
- `#13072 <https://github.com/pytest-dev/pytest/issues/13072>`_: Added support for displaying test session **progress in the terminal tab** using the `OSC 9;4; <https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC>`_ ANSI sequence.
181+
182+
**Note**: *This feature has been disabled by default in version 9.0.2, except on Windows, due to compatibility issues with some terminal emulators.
183+
You may enable it again by passing* ``-p terminalprogress``. *We may enable it by default again once compatibility improves in the future.*
184+
181185
When pytest runs in a supported terminal emulator like ConEmu, Gnome Terminal, Ptyxis, Windows Terminal, Kitty or Ghostty,
182186
you'll see the progress in the terminal tab or window,
183187
allowing you to monitor pytest's progress at a glance.

src/_pytest/config/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ def directory_arg(path: str, optname: str) -> str:
303303
*default_plugins,
304304
"pytester",
305305
"pytester_assertions",
306+
"terminalprogress",
306307
}
307308

308309

src/_pytest/terminal.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import datetime
1717
from functools import partial
1818
import inspect
19-
import os
2019
from pathlib import Path
2120
import platform
2221
import sys
@@ -299,16 +298,10 @@ def mywriter(tags, args):
299298

300299
config.trace.root.setprocessor("pytest:config", mywriter)
301300

302-
if reporter.isatty():
303-
# Some terminals interpret OSC 9;4 as desktop notification,
304-
# skip on those we know (#13896).
305-
should_skip_terminal_progress = (
306-
# iTerm2 (reported on version 3.6.5).
307-
"ITERM_SESSION_ID" in os.environ
308-
)
309-
if not should_skip_terminal_progress:
310-
plugin = TerminalProgressPlugin(reporter)
311-
config.pluginmanager.register(plugin, "terminalprogress")
301+
# See terminalprogress.py.
302+
# On Windows it's safe to load by default.
303+
if sys.platform == "win32":
304+
config.pluginmanager.import_plugin("terminalprogress")
312305

313306

314307
def getreportopt(config: Config) -> str:

src/_pytest/terminalprogress.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# A plugin to register the TerminalProgressPlugin plugin.
2+
#
3+
# This plugin is not loaded by default due to compatibility issues (#13896),
4+
# but can be enabled in one of these ways:
5+
# - The terminal plugin enables it in a few cases where it's safe, and not
6+
# blocked by the user (using e.g. `-p no:terminalprogress`).
7+
# - The user explicitly requests it, e.g. using `-p terminalprogress`.
8+
#
9+
# In a few years, if it's safe, we can consider enabling it by default. Then,
10+
# this file will become unnecessary and can be inlined into terminal.py.
11+
12+
from __future__ import annotations
13+
14+
from _pytest.config import Config
15+
from _pytest.config import hookimpl
16+
from _pytest.terminal import TerminalProgressPlugin
17+
from _pytest.terminal import TerminalReporter
18+
19+
20+
@hookimpl(trylast=True)
21+
def pytest_configure(config: Config) -> None:
22+
reporter: TerminalReporter | None = config.pluginmanager.get_plugin(
23+
"terminalreporter"
24+
)
25+
26+
if reporter is not None and reporter.isatty():
27+
plugin = TerminalProgressPlugin(reporter)
28+
config.pluginmanager.register(plugin, name="terminalprogress-plugin")

testing/test_terminal.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3428,30 +3428,35 @@ def write_raw(s: str, *, flush: bool = False) -> None:
34283428
tr._progress_nodeids_reported = set()
34293429
return tr
34303430

3431-
def test_plugin_registration(self, pytester: pytest.Pytester) -> None:
3432-
"""Test that the plugin is registered correctly on TTY output."""
3431+
@pytest.mark.skipif(sys.platform != "win32", reason="#13896")
3432+
def test_plugin_registration_enabled_by_default(
3433+
self, pytester: pytest.Pytester
3434+
) -> None:
3435+
"""Test that the plugin registration is enabled by default.
3436+
3437+
Currently only on Windows (#13896).
3438+
"""
34333439
# The plugin module should be registered as a default plugin.
34343440
with patch.object(sys.stdout, "isatty", return_value=True):
34353441
config = pytester.parseconfigure()
34363442
plugin = config.pluginmanager.get_plugin("terminalprogress")
34373443
assert plugin is not None
34383444

3445+
def test_plugin_registred_on_all_platforms_when_explicitly_requested(
3446+
self, pytester: pytest.Pytester
3447+
) -> None:
3448+
"""Test that the plugin is registered on any platform if explicitly requested."""
3449+
# The plugin module should be registered as a default plugin.
3450+
with patch.object(sys.stdout, "isatty", return_value=True):
3451+
config = pytester.parseconfigure("-p", "terminalprogress")
3452+
plugin = config.pluginmanager.get_plugin("terminalprogress")
3453+
assert plugin is not None
3454+
34393455
def test_disabled_for_non_tty(self, pytester: pytest.Pytester) -> None:
34403456
"""Test that plugin is disabled for non-TTY output."""
34413457
with patch.object(sys.stdout, "isatty", return_value=False):
3442-
config = pytester.parseconfigure()
3443-
plugin = config.pluginmanager.get_plugin("terminalprogress")
3444-
assert plugin is None
3445-
3446-
def test_disabled_for_iterm2(self, pytester: pytest.Pytester, monkeypatch) -> None:
3447-
"""Should not register the plugin on iTerm2 terminal since it interprets
3448-
OSC 9;4 as desktop notifications, not progress (#13896)."""
3449-
monkeypatch.setenv(
3450-
"ITERM_SESSION_ID", "w0t1p0:3DB6DF06-FE11-40C3-9A66-9E10A193A632"
3451-
)
3452-
with patch.object(sys.stdout, "isatty", return_value=True):
3453-
config = pytester.parseconfigure()
3454-
plugin = config.pluginmanager.get_plugin("terminalprogress")
3458+
config = pytester.parseconfigure("-p", "terminalprogress")
3459+
plugin = config.pluginmanager.get_plugin("terminalprogress-plugin")
34553460
assert plugin is None
34563461

34573462
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)