test_terminalwriter.py
Overview
`test_terminalwriter.py` is a test suite designed to verify the functionality and behavior of the `TerminalWriter` class and related terminal output utilities from the `_pytest._io.terminalwriter` module. This file primarily uses the `pytest` framework along with [unittest.mock](/projects/286/67272) and `pytest`'s own `MonkeyPatch` fixture to simulate various terminal environments, encoding settings, and output scenarios.
The tests ensure that terminal output handling:
Correctly determines terminal width from environment variables or system calls.
Behaves properly across different terminal types (e.g., dumb terminals).
Handles Unicode and encoding edge cases.
Produces correct ANSI markup for colors and styles where supported.
Correctly manages line widths, wide characters, and combining characters.
Applies code highlighting and source code formatting when enabled.
Properly respects environment variables controlling color output (
PY_COLORS,NO_COLOR,FORCE_COLOR).
Detailed Explanations
Test Functions (Module-level)
These standalone functions test utility functions or specific behaviors:
test_terminal_width_COLUMNS(monkeypatch: MonkeyPatch) -> NoneTests that
get_terminal_width()correctly returns the terminal width based on theCOLUMNSenvironment variable.Usage:
monkeypatch.setenv("COLUMNS", "42") assert terminalwriter.get_terminal_width() == 42test_terminalwriter_width_bogus(monkeypatch: MonkeyPatch) -> NoneVerifies that when
shutil.get_terminal_size()returns an unexpected size,TerminalWriterdefaults to width 80.test_terminalwriter_computes_width(monkeypatch: MonkeyPatch) -> NoneChecks if
TerminalWriter.fullwidthproperty is correctly set usingget_terminal_width().test_terminalwriter_dumb_term_no_markup(monkeypatch: MonkeyPatch) -> NoneSimulates a dumb terminal environment (
TERM=dumb) to verify that no markup is applied (hasmarkupis False).test_terminalwriter_not_unicode() -> NoneEnsures that when the output file does not support Unicode encoding, Unicode characters are escaped properly.
test_attr_hasmarkup()Checks that when
hasmarkupis set to True, ANSI escape sequences for styles (e.g., bold) appear in output.assert_color(expected: bool, default: bool | None = None) -> NoneHelper function to assert whether markup is applied based on environment and terminal conditions.
test_should_do_markup_PY_COLORS_eq_1(monkeypatch: MonkeyPatch) -> NoneTests that setting
PY_COLORS=1enables markup.test_should_not_do_markup_PY_COLORS_eq_0(monkeypatch: MonkeyPatch) -> NoneTests that
PY_COLORS=0disables markup.test_should_not_do_markup_NO_COLOR(monkeypatch: MonkeyPatch) -> NoneTests that
NO_COLOR=1disables markup.test_should_do_markup_FORCE_COLOR(monkeypatch: MonkeyPatch) -> NoneTests that
FORCE_COLOR=1enables markup even if defaults say otherwise.test_NO_COLOR_and_FORCE_COLOR(...)Parametrized test to verify combinations of
NO_COLORandFORCE_COLORenvironment variables.test_empty_NO_COLOR_and_FORCE_COLOR_ignored(monkeypatch: MonkeyPatch) -> NoneChecks behavior when both variables are set to empty strings.
test_code_highlight(...)Parametrized test verifying that source code highlighting behaves correctly depending on
hasmarkupandcode_highlightflags.test_highlight_empty_source() -> NoneVerifies that calling
_write_sourceon empty source code does not crash.
Class: TestTerminalWriter
Test class containing tests that exercise `TerminalWriter` instances created with different writable file-like objects.
Fixture:
tw(self, request, tmp_path: Path) -> Generator[terminalwriter.TerminalWriter]Provides a
TerminalWriterinstance backed by either a temporary file or aStringIOobject, depending on parameterization.When
request.param == "path": creates a temporary UTF-8 file.When
request.param == "stringio": uses an in-memory string buffer.
Adds convenience methods:
getlines()to read all lines from the underlying file/buffer.getvalue()returns all content as a single string.
test_line(self, tw) -> NoneTests that
tw.line()writes a single line followed by a newline.test_line_unicode(self, tw) -> NoneTests writing a Unicode string line.
test_sep_no_title(self, tw) -> NoneTests the separator line with no title, verifying line length.
test_sep_with_title(self, tw) -> NoneTests separator line with a title in the middle.
test_sep_longer_than_width(self, tw) -> NoneTests behavior when separator title is longer than the full width.
test_markup(self, tw, bold: bool, color: str) -> NoneTests
markup()method with combinations of bold and color (red, green). Skips on Windows because of lack of native ANSI.test_markup_bad(self, tw) -> NoneEnsures that invalid markup keyword arguments raise
ValueError.test_line_write_markup(self, tw) -> NoneTests writing lines and text with markup enabled.
test_attr_fullwidth(self, tw) -> NoneTests the effect of setting the
fullwidthattribute on separator line length.
Class: TestTerminalWriterLineWidth
Tests related to tracking the width of the current line in `TerminalWriter`.
test_init(self) -> NoneVerifies initial line width is zero.
test_update(self) -> NoneVerifies width updates after writing a simple string.
test_update_with_newline(self) -> NoneTests line width resets after newline characters.
test_update_with_wide_text(self) -> NoneTests width calculation with wide (double-width) Unicode characters.
test_composed(self) -> NoneTests width calculation for composed characters (e.g., accented
éas one character).test_combining(self) -> NoneTests width calculation for combining Unicode characters (e.g., letter + accent as two code points but one visible character).
Important Implementation Details and Algorithms
Terminal Width Detection
The tests verify that terminal width is sourced from:
The
COLUMNSenvironment variable.shutil.get_terminal_size().Default fallback width (80) in case of bogus or unavailable values.
Unicode and Encoding Handling
Tests check how
TerminalWritergracefully handles output to files that do not support Unicode encoding by escaping Unicode characters.Markup and ANSI Escape Sequences
The
TerminalWritersupports markup for colors and styles (bold, red, green). The tests simulate environment variables and terminal types to assert when markup is enabled or disabled.Line Width Calculation
The tests verify that
TerminalWritercorrectly tracks the width of the current line taking into account:Newline characters (reset width).
Wide characters that occupy two columns (e.g., East Asian wide characters).
Composed characters and combining marks (counted as one visible character width).
Code Highlighting
The
_write_source()method inTerminalWritersupports source code highlighting. The tests verify correct output formatting when highlight is enabled or disabled, and handle empty source gracefully.
Interaction with Other Parts of the System
This test suite validates the behavior of the
TerminalWriterclass from_pytest._io.terminalwriter. That class is part of the Pytest internals responsible for formatting terminal output during test runs.It indirectly interacts with:
Environment variables affecting terminal behavior.
Low-level terminal capabilities detection (
shutil.get_terminal_size, environment variables).Python’s I/O system via file-like objects (e.g.,
StringIO, temporary files).The ANSI markup system used to colorize terminal output.
These tests ensure that Pytest’s terminal output is robust across different platforms (Unix, Windows), terminal types, and encoding environments.
Usage Examples (from the tests)
from _pytest._io import terminalwriter
# Create a TerminalWriter instance writing to standard output or a file
tw = terminalwriter.TerminalWriter()
# Write a simple line
tw.line("Hello, world")
# Write a separator line of width 60 with a title
tw.sep("-", "Section 1", fullwidth=60)
# Write colored, bold text if markup is enabled
if tw.hasmarkup:
tw.line(tw.markup("Warning!", red=True, bold=True))
# Write unicode text that may be escaped if encoding unsupported
tw.write("hello 🌀 wôrld אבג\n")
# Enable code highlighting and write source
tw.code_highlight = True
tw._write_source(["assert 0"])
Mermaid Class Diagram
classDiagram
class TestTerminalWriter {
+tw(self, request, tmp_path: Path) Generator[TerminalWriter]
+test_line(self, tw)
+test_line_unicode(self, tw)
+test_sep_no_title(self, tw)
+test_sep_with_title(self, tw)
+test_sep_longer_than_width(self, tw)
+test_markup(self, tw, bold: bool, color: str)
+test_markup_bad(self, tw)
+test_line_write_markup(self, tw)
+test_attr_fullwidth(self, tw)
}
class TestTerminalWriterLineWidth {
+test_init(self)
+test_update(self)
+test_update_with_newline(self)
+test_update_with_wide_text(self)
+test_composed(self)
+test_combining(self)
}
Summary
`test_terminalwriter.py` is a comprehensive test module ensuring that the `TerminalWriter` class behaves as expected across diverse terminal environments, encodings, and output scenarios. It covers terminal width calculation, Unicode handling, markup/ANSI styling, line width tracking, and source code highlighting, providing confidence that Pytest’s terminal output is consistent and visually correct.
This file is integral to Pytest’s internal I/O layer testing, safeguarding user experience during test runs on various platforms and configurations.