|
2 | 2 | # For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
|
3 | 3 | # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
|
4 | 4 |
|
| 5 | +from __future__ import annotations |
| 6 | + |
| 7 | +import io |
5 | 8 | import os
|
| 9 | +import sys |
| 10 | +import warnings |
6 | 11 | from pathlib import Path
|
7 | 12 | from typing import Any, NoReturn
|
8 | 13 | from unittest import mock
|
9 | 14 | from unittest.mock import patch
|
10 | 15 |
|
| 16 | +import pytest |
11 | 17 | from pytest import CaptureFixture
|
12 | 18 |
|
13 |
| -from pylint.lint.pylinter import MANAGER, PyLinter |
| 19 | +from pylint.lint.pylinter import ( |
| 20 | + FORCE_COLOR, |
| 21 | + MANAGER, |
| 22 | + NO_COLOR, |
| 23 | + PY_COLORS, |
| 24 | + WARN_BOTH_COLOR_SET, |
| 25 | + PyLinter, |
| 26 | + _handle_force_color_no_color, |
| 27 | +) |
| 28 | +from pylint.reporters.text import ColorizedTextReporter, TextReporter |
14 | 29 | from pylint.utils import FileState
|
15 | 30 |
|
| 31 | +COLORIZED_REPORTERS = "colorized_reporters" |
| 32 | +TEXT_REPORTERS = "text_reporters" |
| 33 | +STDOUT_TEXT = "stdout" |
| 34 | + |
16 | 35 |
|
17 | 36 | def raise_exception(*args: Any, **kwargs: Any) -> NoReturn:
|
18 | 37 | raise ValueError
|
@@ -68,3 +87,133 @@ def test_open_pylinter_prefer_stubs(linter: PyLinter) -> None:
|
68 | 87 | assert MANAGER.prefer_stubs
|
69 | 88 | finally:
|
70 | 89 | MANAGER.prefer_stubs = False
|
| 90 | + |
| 91 | + |
| 92 | +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: |
| 93 | + if metafunc.function.__name__ != test_handle_force_color_no_color.__name__: |
| 94 | + return |
| 95 | + |
| 96 | + if ( |
| 97 | + TEXT_REPORTERS not in metafunc.fixturenames |
| 98 | + or COLORIZED_REPORTERS not in metafunc.fixturenames |
| 99 | + ): |
| 100 | + warnings.warn( |
| 101 | + f"Missing fixture {TEXT_REPORTERS} or {COLORIZED_REPORTERS} in" |
| 102 | + f" {test_handle_force_color_no_color.function.__name__}??", |
| 103 | + stacklevel=2, |
| 104 | + ) |
| 105 | + return |
| 106 | + |
| 107 | + parameters = [] |
| 108 | + |
| 109 | + reporter_combinations = [ |
| 110 | + ("file", STDOUT_TEXT), |
| 111 | + ("file",), |
| 112 | + (STDOUT_TEXT,), |
| 113 | + ("",), |
| 114 | + ] |
| 115 | + |
| 116 | + for tr in list(reporter_combinations): |
| 117 | + for cr in list(reporter_combinations): |
| 118 | + tr = tuple(t for t in tr if t) |
| 119 | + cr = tuple(t for t in cr if t) |
| 120 | + |
| 121 | + total_reporters = len(tr) + len(cr) |
| 122 | + unique_reporters = len(set(tr + cr)) |
| 123 | + |
| 124 | + if total_reporters == 0: |
| 125 | + continue |
| 126 | + |
| 127 | + if unique_reporters != total_reporters: |
| 128 | + continue |
| 129 | + |
| 130 | + parameters.append((tuple(tr), tuple(cr))) |
| 131 | + |
| 132 | + metafunc.parametrize( |
| 133 | + f"{TEXT_REPORTERS}, {COLORIZED_REPORTERS}", parameters, ids=repr |
| 134 | + ) |
| 135 | + |
| 136 | + |
| 137 | +@pytest.mark.parametrize( |
| 138 | + "no_color", |
| 139 | + [True, False], |
| 140 | + ids=lambda no_color: f"{no_color=}", |
| 141 | +) |
| 142 | +@pytest.mark.parametrize( |
| 143 | + "py_colors", |
| 144 | + [True, False], |
| 145 | + ids=lambda py_colors: f"{py_colors=}", |
| 146 | +) |
| 147 | +@pytest.mark.parametrize( |
| 148 | + "force_color", |
| 149 | + [True, False], |
| 150 | + ids=lambda force_color: f"{force_color=}", |
| 151 | +) |
| 152 | +def test_handle_force_color_no_color( |
| 153 | + monkeypatch: pytest.MonkeyPatch, |
| 154 | + recwarn: pytest.WarningsRecorder, |
| 155 | + no_color: bool, |
| 156 | + py_colors: bool, |
| 157 | + force_color: bool, |
| 158 | + text_reporters: tuple[str], |
| 159 | + colorized_reporters: tuple[str], |
| 160 | +) -> None: |
| 161 | + monkeypatch.setenv(NO_COLOR, "1" if no_color else "") |
| 162 | + monkeypatch.setenv(FORCE_COLOR, "1" if force_color else "") |
| 163 | + monkeypatch.setenv(PY_COLORS, "1" if py_colors else "") |
| 164 | + |
| 165 | + force_color = force_color or py_colors |
| 166 | + |
| 167 | + if STDOUT_TEXT in text_reporters or STDOUT_TEXT in colorized_reporters: |
| 168 | + monkeypatch.setattr(sys, STDOUT_TEXT, io.TextIOWrapper(io.BytesIO())) |
| 169 | + |
| 170 | + reporters = [] |
| 171 | + for reporter, group in ( |
| 172 | + (TextReporter, text_reporters), |
| 173 | + (ColorizedTextReporter, colorized_reporters), |
| 174 | + ): |
| 175 | + for name in group: |
| 176 | + if name == STDOUT_TEXT: |
| 177 | + reporters.append(reporter()) |
| 178 | + if name == "file": |
| 179 | + reporters.append(reporter(io.TextIOWrapper(io.BytesIO()))) |
| 180 | + |
| 181 | + _handle_force_color_no_color(reporters) |
| 182 | + |
| 183 | + if no_color and force_color: |
| 184 | + # Both NO_COLOR and FORCE_COLOR are set; expecting a warning. |
| 185 | + both_color_warning = [ |
| 186 | + idx |
| 187 | + for idx, w in enumerate(recwarn.list) |
| 188 | + if WARN_BOTH_COLOR_SET in str(w.message) |
| 189 | + ] |
| 190 | + assert len(both_color_warning) == 1 |
| 191 | + recwarn.list.pop(both_color_warning[0]) |
| 192 | + |
| 193 | + if no_color: |
| 194 | + # No ColorizedTextReporter expected to be connected to stdout. |
| 195 | + assert all( |
| 196 | + not isinstance(rep, ColorizedTextReporter) |
| 197 | + for rep in reporters |
| 198 | + if rep.out.buffer is sys.stdout.buffer |
| 199 | + ) |
| 200 | + |
| 201 | + if STDOUT_TEXT in colorized_reporters: |
| 202 | + assert len(recwarn.list) == 1 # expect a warning for overriding stdout |
| 203 | + else: |
| 204 | + assert len(recwarn.list) == 0 # no warning expected |
| 205 | + elif force_color: |
| 206 | + # No TextReporter expected to be connected to stdout. |
| 207 | + # pylint: disable=unidiomatic-typecheck # Want explicit type check. |
| 208 | + assert all( |
| 209 | + type(rep) is not TextReporter |
| 210 | + for rep in reporters |
| 211 | + if rep.out.buffer is sys.stdout.buffer |
| 212 | + ) |
| 213 | + |
| 214 | + if STDOUT_TEXT in text_reporters: |
| 215 | + assert len(recwarn.list) == 1 # expect a warning for overriding stdout |
| 216 | + else: |
| 217 | + assert len(recwarn.list) == 0 # no warning expected |
| 218 | + else: |
| 219 | + assert len(recwarn.list) == 0 # no warning expected |
0 commit comments