Skip to content

Commit d3de4a4

Browse files
authored
Add back support for warn_unused_configs (#20801)
Fixes #7998 This was disabled in incremental mode (i.e. almost always, since this is now the default), because we didn't clone options for suppressed dependencies, but now because we are doing this (for the purpose of fixing other issues), there is no reason to keep this disabled (IMO this is a nice feature to keep your config clean). Few more things here: * I moved the logic inside `build.build()`, first it is wrong to show this warning in case of blocking errors (since we may not processed all files yet), second it is easier to test. * I am now using more standard message formatting `path: note: ...` * I am updating couple comments I forgot to update in previous PRs (sorry)
1 parent 60f1570 commit d3de4a4

File tree

5 files changed

+74
-35
lines changed

5 files changed

+74
-35
lines changed

mypy/build.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
from mypy.report import Reports # Avoid unconditional slow import
132132

133133
from mypy import errorcodes as codes
134-
from mypy.config_parser import parse_mypy_comments
134+
from mypy.config_parser import get_config_module_names, parse_mypy_comments
135135
from mypy.fixup import fixup_module
136136
from mypy.freetree import free_tree
137137
from mypy.fscache import FileSystemCache
@@ -481,6 +481,7 @@ def build_inner(
481481
dump_timing_stats(options.timing_stats, graph)
482482
if options.line_checking_stats is not None:
483483
dump_line_checking_stats(options.line_checking_stats, graph)
484+
warn_unused_configs(options, flush_errors)
484485
return BuildResult(manager, graph)
485486
finally:
486487
t0 = time.time()
@@ -505,6 +506,19 @@ def build_inner(
505506
record_missing_stub_packages(options.cache_dir, manager.missing_stub_packages)
506507

507508

509+
def warn_unused_configs(
510+
options: Options, flush_errors: Callable[[str | None, list[str], bool], None]
511+
) -> None:
512+
if options.warn_unused_configs and options.unused_configs and not options.non_interactive:
513+
unused = get_config_module_names(
514+
options.config_file,
515+
[glob for glob in options.per_module_options.keys() if glob in options.unused_configs],
516+
)
517+
flush_errors(
518+
None, ["{}: note: unused section(s): {}".format(options.config_file, unused)], False
519+
)
520+
521+
508522
def default_data_dir() -> str:
509523
"""Returns directory containing typeshed directory."""
510524
return os.path.dirname(__file__)
@@ -3789,7 +3803,7 @@ def load_graph(
37893803
manager.missing_modules[dep] = SuppressionReason.NOT_FOUND
37903804
# TODO: for now we skip this in the daemon as a performance optimization.
37913805
# This however creates a correctness issue, see #7777 and State.is_fresh().
3792-
if not manager.use_fine_grained_cache():
3806+
if not manager.use_fine_grained_cache() or manager.options.warn_unused_configs:
37933807
manager.import_options[dep] = manager.options.clone_for_module(
37943808
dep
37953809
).dep_import_options()
@@ -3839,8 +3853,8 @@ def load_graph(
38393853
graph[newst.id] = newst
38403854
new.append(newst)
38413855
# There are two things we need to do after the initial load loop. One is up-suppress
3842-
# modules that are back in graph. We need to do this after the loop to cover an edge
3843-
# case where a namespace package ancestor is shared by a typed and an untyped package.
3856+
# modules that are back in graph. We need to do this after the loop to cover edge cases
3857+
# like where a namespace package ancestor is shared by a typed and an untyped package.
38443858
for st in graph.values():
38453859
for dep in st.suppressed.copy():
38463860
if dep in graph:

mypy/ipc.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ class IPCBase:
5353
This contains logic shared between the client and server, such as reading
5454
and writing.
5555
We want to be able to send multiple "messages" over a single connection and
56-
to be able to separate the messages. We do this by encoding the messages
57-
in an alphabet that does not contain spaces, then adding a space for
58-
separation. The last framed message is also followed by a space.
56+
to be able to separate the messages. We do this by prefixing each message
57+
with its size in a fixed format.
5958
"""
6059

6160
connection: _IPCHandle

mypy/main.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@
2323
sys.exit(2)
2424

2525
from mypy import build, defaults, state, util
26-
from mypy.config_parser import (
27-
get_config_module_names,
28-
parse_config_file,
29-
parse_version,
30-
validate_package_allow_list,
31-
)
26+
from mypy.config_parser import parse_config_file, parse_version, validate_package_allow_list
3227
from mypy.defaults import RECURSION_LIMIT
3328
from mypy.error_formatter import OUTPUT_CHOICES
3429
from mypy.errors import CompileError
@@ -221,26 +216,6 @@ def flush_errors(filename: str | None, new_messages: list[str], serious: bool) -
221216
blockers = True
222217
if not e.use_stdout:
223218
serious = True
224-
if (
225-
options.warn_unused_configs
226-
and options.unused_configs
227-
and not options.incremental
228-
and not options.non_interactive
229-
):
230-
print(
231-
"Warning: unused section(s) in {}: {}".format(
232-
options.config_file,
233-
get_config_module_names(
234-
options.config_file,
235-
[
236-
glob
237-
for glob in options.per_module_options.keys()
238-
if glob in options.unused_configs
239-
],
240-
),
241-
),
242-
file=stderr,
243-
)
244219
maybe_write_junit_xml(time.time() - t0, serious, messages, messages_by_file, options)
245220
return res, messages, blockers
246221

test-data/unit/check-incremental.test

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7929,6 +7929,58 @@ from a import b # type: ignore[attr-defined]
79297929
main:2: error: Unused "type: ignore" comment
79307930
[out2]
79317931

7932+
[case testConfigWarnUnusedSectionIncremental]
7933+
# flags: --config-file=tmp/mypy.ini
7934+
import m
7935+
[file m.py]
7936+
import a
7937+
[file m.py.2]
7938+
import a # touch
7939+
[file a.py]
7940+
import foo # type: ignore
7941+
[file mypy.ini]
7942+
\[mypy]
7943+
warn_unused_configs = true
7944+
\[mypy-bar]
7945+
\[mypy-foo]
7946+
[file mypy.ini.3]
7947+
\[mypy]
7948+
warn_unused_configs = true
7949+
\[mypy-foo]
7950+
[out]
7951+
tmp/mypy.ini: note: unused section(s): [mypy-bar]
7952+
[out2]
7953+
tmp/mypy.ini: note: unused section(s): [mypy-bar]
7954+
[out3]
7955+
7956+
[case testConfigWarnUnusedSectionIncrementalTOML]
7957+
# flags: --config-file tmp/pyproject.toml
7958+
import m
7959+
[file m.py]
7960+
import a
7961+
[file m.py.2]
7962+
import a # touch
7963+
[file a.py]
7964+
import foo # type: ignore
7965+
[file pyproject.toml]
7966+
\[tool.mypy]
7967+
warn_unused_configs = true
7968+
\[[tool.mypy.overrides]]
7969+
module = "bar"
7970+
\[[tool.mypy.overrides]]
7971+
module = "foo"
7972+
warn_unreachable = true
7973+
[file pyproject.toml.3]
7974+
\[tool.mypy]
7975+
warn_unused_configs = true
7976+
\[[tool.mypy.overrides]]
7977+
module = "foo"
7978+
[out]
7979+
tmp/pyproject.toml: note: unused section(s): module = ['bar']
7980+
[out2]
7981+
tmp/pyproject.toml: note: unused section(s): module = ['bar']
7982+
[out3]
7983+
79327984
[case testAddedMissingModuleSkip]
79337985
# flags: --follow-imports=skip
79347986
import mod

test-data/unit/cmdline.test

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,6 @@ variable has type "bytes")
535535
[file mypy.ini]
536536
\[mypy]
537537
warn_unused_configs = True
538-
incremental = False
539538
\[mypy-bar]
540539
\[mypy-foo]
541540
\[mypy-baz.*]
@@ -555,7 +554,7 @@ incremental = False
555554
[file spam/__init__.py]
556555
[file spam/eggs.py]
557556
[out]
558-
Warning: unused section(s) in mypy.ini: [mypy-bar], [mypy-baz.*], [mypy-emarg.*], [mypy-emarg.hatch], [mypy-a.*.c], [mypy-a.x.b]
557+
mypy.ini: note: unused section(s): [mypy-bar], [mypy-baz.*], [mypy-emarg.*], [mypy-emarg.hatch], [mypy-a.*.c], [mypy-a.x.b]
559558
== Return code: 0
560559

561560
[case testPackageRootEmpty]

0 commit comments

Comments
 (0)