diff --git a/src/python/pants/backend/python/typecheck/mypy/rules.py b/src/python/pants/backend/python/typecheck/mypy/rules.py index a779a92056b..4f4476086db 100644 --- a/src/python/pants/backend/python/typecheck/mypy/rules.py +++ b/src/python/pants/backend/python/typecheck/mypy/rules.py @@ -319,6 +319,11 @@ async def mypy_typecheck_partition( env = { "PEX_EXTRA_SYS_PATH": ":".join(all_used_source_roots), "MYPYPATH": ":".join(all_used_source_roots), + # Force a fixed terminal width. This is effectively infinite, disabling mypy's + # builtin truncation and line wrapping. Terminals do an acceptable job of soft-wrapping + # diagnostic text and source code is typically already hard-wrapped to a limited width. + # (Unique random number to make it easier to search for the source of this setting.) + "MYPY_FORCE_TERMINAL_WIDTH": "642092230765939", } process = await Get( diff --git a/src/python/pants/backend/python/typecheck/mypy/rules_integration_test.py b/src/python/pants/backend/python/typecheck/mypy/rules_integration_test.py index 40fdcc6bce3..7d23da77fdf 100644 --- a/src/python/pants/backend/python/typecheck/mypy/rules_integration_test.py +++ b/src/python/pants/backend/python/typecheck/mypy/rules_integration_test.py @@ -3,6 +3,7 @@ from __future__ import annotations +import re from textwrap import dedent import pytest @@ -872,3 +873,31 @@ def test_determine_python_files() -> None: assert determine_python_files(["f.py", "f.pyi"]) == ("f.pyi",) assert determine_python_files(["f.pyi", "f.py"]) == ("f.pyi",) assert determine_python_files(["f.json"]) == () + + +def test_colors_and_formatting(rule_runner: RuleRunner) -> None: + rule_runner.write_files( + { + f"{PACKAGE}/f.py": dedent( + """\ + class incredibly_long_type_name_to_force_wrapping_if_mypy_wrapped_error_messages_12345678901234567890123456789012345678901234567890: + pass + + x = incredibly_long_type_name_to_force_wrapping_if_mypy_wrapped_error_messages_12345678901234567890123456789012345678901234567890() + x.incredibly_long_attribute_name_to_force_wrapping_if_mypy_wrapped_error_messages_12345678901234567890123456789012345678901234567890 + """ + ), + f"{PACKAGE}/BUILD": "python_sources()", + } + ) + tgt = rule_runner.get_target(Address(PACKAGE, relative_file_path="f.py")) + + result = run_mypy(rule_runner, [tgt], extra_args=["--colors=true", "--mypy-args=--pretty"]) + + assert len(result) == 1 + assert result[0].exit_code == 1 + # all one line + assert re.search( + "error:.*incredibly_long_type_name.*incredibly_long_attribute_name", result[0].stdout + ) + assert result[0].report == EMPTY_DIGEST