Skip to content

Enable pretty by default #19510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -910,10 +910,10 @@ in error messages.

See :ref:`error-codes` for more information.

.. option:: --pretty
.. option:: --no-pretty

Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.
Disable pretty error messages and use the old, plain output format.
Pretty-printing is enable by default.

.. option:: --no-color-output

Expand Down
3 changes: 2 additions & 1 deletion docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -896,10 +896,11 @@ These options may only be set in the global section (``[mypy]``).
.. confval:: pretty

:type: boolean
:default: False
:default: True

Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.
Pretty printing is enabled by default, but can be disabled.

.. confval:: color_output

Expand Down
15 changes: 7 additions & 8 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,21 +991,20 @@ def add_invertible_flag(
help="Show links to error code documentation",
group=error_group,
)
add_invertible_flag(
"--pretty",
default=False,
help="Use visually nicer output in error messages:"
" Use soft word wrap, show source code snippets,"
" and show error location markers",
group=error_group,
)
add_invertible_flag(
"--no-color-output",
dest="color_output",
default=True,
help="Do not colorize error messages",
group=error_group,
)
add_invertible_flag(
"--no-pretty",
default=True,
dest="pretty",
help="Disable pretty error message",
group=error_group,
)
add_invertible_flag(
"--no-error-summary",
dest="error_summary",
Expand Down
2 changes: 1 addition & 1 deletion mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def __init__(self) -> None:
self.hide_error_codes = False
self.show_error_code_links = False
# Use soft word wrap and show trimmed source snippets with error location markers.
self.pretty = False
self.pretty = True
self.dump_graph = False
self.dump_deps = False
self.logical_deps = False
Expand Down
5 changes: 4 additions & 1 deletion mypy/test/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ def parse_options(

if flags:
flag_list = flags.group(1).split()
if "--pretty" not in flag_list:
flag_list.append("--no-pretty")
flag_list.append("--no-site-packages") # the tests shouldn't need an installed Python
targets, options = process_options(flag_list, require_targets=False)
if targets:
Expand All @@ -350,11 +352,12 @@ def parse_options(
if "--show-error-codes" not in flag_list:
options.hide_error_codes = True
else:
flag_list = []
options = Options()
options.pretty = False
options.error_summary = False
options.hide_error_codes = True
options.force_union_syntax = True
flag_list = []

# Allow custom python version to override testfile_pyversion.
if all(flag.split("=")[0] != "--python-version" for flag in flag_list):
Expand Down
9 changes: 7 additions & 2 deletions mypy/test/testcmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,13 @@ def parse_args(line: str) -> list[str]:
"""
m = re.match("# cmd: mypy (.*)$", line)
if not m:
return [] # No args; mypy will spit out an error.
return m.group(1).split()
return ["--no-pretty"] # No args; mypy will spit out an error.
args = m.group(1).split()

if "--pretty" not in args:
args.append("--no-pretty")

return args


def parse_cwd(line: str) -> str | None:
Expand Down
12 changes: 12 additions & 0 deletions mypy/test/testdaemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ def parse_script(input: list[str]) -> list[list[str]]:
def run_cmd(input: str) -> tuple[int, str]:
if input[1:].startswith("mypy run --") and "--show-error-codes" not in input:
input += " --hide-error-codes"
is_pretty_test = "# NO-MODIFY" in input
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I must be missing something - why won't just checking for --pretty flag do? Yes, it will deviate from normal behavior, but be consistent with all other tests - essentially sticking to old default unless requested otherwise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @sterliakov , this is still my main approach and it is also partly working in the this test-runner to maintain the consistent behavior with all other test-runners.However, I discovered a critical technical constraint: the dmypy client itself does not accept the --pretty or --no-pretty flags.

The formatting flags must be directly passed to the server, which only worked in these two ways for me:
- During startup: $ dmypy start -- --no-pretty
- During one-shot run: $ dmypy run -- --no-pretty

Because the testcases contains a mix of commands where the flag will and won't work, I had to make #NO-MODIFY as the magic comment to recognize where to not modify the command.

For demonstration:

[case testDaemonRecheck]
$ dmypy start -- --follow-imports=error --no-error-summary
Daemon started
$ dmypy check foo.py bar.py
$ dmypy recheck
$ dmypy recheck --update foo.py --remove bar.py sir_not_appearing_in_this_film.py
foo.py:1: error: Import of "bar" ignored  [misc]
foo.py:1: note: (Using --follow-imports=error, module not passed on command line)
== Return code: 1
$ dmypy recheck --update bar.py
$ dmypy recheck --update sir_not_appearing_in_this_film.py
$ dmypy recheck --update --remove
$ dmypy stop
Daemon stopped
[file foo.py]

In this case, my first approach was to insert the --pretty flag in all of them. But dmypy recheck threw an unrecognized argument error. So I realized I cannot insert any flag in the commands following dmypy start...
Therefore, I preferred to adding --pretty flag during startup. But then the test-runner logic detecting so such --pretty flag in the other commands automatically injects the --no-pretty flag which also throws an unrecognized argument error. This led to the realization, that I also need to mark these commands someway, that the test-runner doesn't inject --no-pretty in them. The best I could think of was a magic comment #NO-MODIFY which I can use to detect these lines where the test-runner shouldn't be interfering.

I understand that this is a very bare-bones workaround, and I am open to any suggestions to make it cleaner.

modified_input = input.replace("# NO-MODIFY", "").strip()
cond1 = "--pretty" not in modified_input
cond2 = modified_input.startswith(("dmypy run", "dmypy check"))
cond3 = not is_pretty_test
if cond1 and cond2 and cond3:
parts = modified_input.split(" ", 2)
command, subcommand = parts[0], parts[1]
args = parts[2] if len(parts) > 2 else ""
input = f"{command} {subcommand} {args} --no-pretty".strip()
else:
input = modified_input
if input.startswith("dmypy "):
input = sys.executable + " -m mypy." + input
if input.startswith("mypy "):
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testerrorstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def test_error_stream(testcase: DataDrivenTestCase) -> None:
The argument contains the description of the test case.
"""
options = Options()
options.pretty = False
options.show_traceback = True
options.hide_error_codes = True

Expand Down
7 changes: 5 additions & 2 deletions mypy/test/testpep561.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,8 @@ def parse_pkgs(comment: str) -> tuple[list[str], list[str]]:
def parse_mypy_args(line: str) -> list[str]:
m = re.match("# flags: (.*)$", line)
if not m:
return [] # No args; mypy will spit out an error.
return m.group(1).split()
return ["--no-pretty"] # No args; mypy will spit out an error.
args = m.group(1).split()
args.append("--no-pretty")

return args
6 changes: 6 additions & 0 deletions mypy/test/testpythoneval.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
"--allow-empty-bodies",
"--test-env", # Speeds up some checks
]

mypy_cmdline.append("--no-pretty")

interpreter = python3_path
mypy_cmdline.append(f"--python-version={'.'.join(map(str, PYTHON3_VERSION))}")

Expand All @@ -69,6 +72,9 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
sys.version_info.minor,
):
return
if "--pretty" in additional_flags:
mypy_cmdline.remove("--no-pretty")

mypy_cmdline.extend(additional_flags)

# Write the program to a file.
Expand Down
10 changes: 8 additions & 2 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2581,13 +2581,17 @@ def test_mypy_build(self) -> None:
output = run_stubtest(stub="+", runtime="", options=[])
assert output == (
"error: not checking stubs due to failed mypy compile:\n{}.pyi:1: "
"error: Invalid syntax [syntax]\n".format(TEST_MODULE_NAME)
"error: Invalid syntax [syntax]\n"
" +\n"
" ^\n".format(TEST_MODULE_NAME)
)

output = run_stubtest(stub="def f(): ...\ndef f(): ...", runtime="", options=[])
assert output == (
"error: not checking stubs due to mypy build errors:\n{}.pyi:2: "
'error: Name "f" already defined on line 1 [no-redef]\n'.format(TEST_MODULE_NAME)
'error: Name "f" already defined on line 1 [no-redef]\n'
" def f(): ...\n"
" ^~~~~~~~~~~~\n".format(TEST_MODULE_NAME)
)

def test_missing_stubs(self) -> None:
Expand Down Expand Up @@ -2665,6 +2669,8 @@ def test_config_file_error_codes(self) -> None:
assert output == (
"error: not checking stubs due to mypy build errors:\n"
'test_module.pyi:1: error: Name "SOME_GLOBAL_CONST" is not defined [name-defined]\n'
" temp = SOME_GLOBAL_CONST\n"
" ^~~~~~~~~~~~~~~~~\n"
)

config_file = "[mypy]\ndisable_error_code = name-defined\n"
Expand Down
Loading