Skip to content

Commit 80c09d5

Browse files
authored
Remove show_none_errors and strict_optional_whitelist (#13507)
These are somewhat buggy and modern per-module options should be preferred. I can't find any use of strict_optional_whitelist. There is some use of show_none_errors, but it's all set to True; I think people are just worried and cargo culting and want mypy to really, actually give them all the errors. Fixes #6514, fixes #2396
1 parent caff030 commit 80c09d5

10 files changed

+7
-116
lines changed

docs/source/config_file.rst

-8
Original file line numberDiff line numberDiff line change
@@ -574,14 +574,6 @@ Suppressing errors
574574
Note: these configuration options are available in the config file only. There is
575575
no analog available via the command line options.
576576

577-
.. confval:: show_none_errors
578-
579-
:type: boolean
580-
:default: True
581-
582-
Shows errors related to strict ``None`` checking, if the global :confval:`strict_optional`
583-
flag is enabled.
584-
585577
.. confval:: ignore_errors
586578

587579
:type: boolean

mypy/checker.py

+1-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import fnmatch
65
import itertools
76
from collections import defaultdict
87
from contextlib import contextmanager, nullcontext
@@ -327,8 +326,6 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
327326
current_node_deferred = False
328327
# Is this file a typeshed stub?
329328
is_typeshed_stub = False
330-
# Should strict Optional-related errors be suppressed in this file?
331-
suppress_none_errors = False # TODO: Get it from options instead
332329
options: Options
333330
# Used for collecting inferred attribute types so that they can be checked
334331
# for consistency.
@@ -391,12 +388,7 @@ def __init__(
391388
self.is_stub = tree.is_stub
392389
self.is_typeshed_stub = is_typeshed_file(path)
393390
self.inferred_attribute_types = None
394-
if options.strict_optional_whitelist is None:
395-
self.suppress_none_errors = not options.show_none_errors
396-
else:
397-
self.suppress_none_errors = not any(
398-
fnmatch.fnmatch(path, pattern) for pattern in options.strict_optional_whitelist
399-
)
391+
400392
# If True, process function definitions. If False, don't. This is used
401393
# for processing module top levels in fine-grained incremental mode.
402394
self.recurse_into_functions = True
@@ -5604,8 +5596,6 @@ def check_subtype(
56045596
subtype, supertype, context, msg_text, subtype_label, supertype_label, code=code
56055597
):
56065598
return False
5607-
if self.should_suppress_optional_error([subtype]):
5608-
return False
56095599
extra_info: list[str] = []
56105600
note_msg = ""
56115601
notes: list[str] = []
@@ -5705,9 +5695,6 @@ def contains_none(self, t: Type) -> bool:
57055695
)
57065696
)
57075697

5708-
def should_suppress_optional_error(self, related_types: list[Type]) -> bool:
5709-
return self.suppress_none_errors and any(self.contains_none(t) for t in related_types)
5710-
57115698
def named_type(self, name: str) -> Instance:
57125699
"""Return an instance type with given name and implicit Any type args.
57135700

mypy/checkexpr.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -2032,8 +2032,6 @@ def check_arg(
20322032
):
20332033
self.msg.concrete_only_call(callee_type, context)
20342034
elif not is_subtype(caller_type, callee_type, options=self.chk.options):
2035-
if self.chk.should_suppress_optional_error([caller_type, callee_type]):
2036-
return
20372035
code = self.msg.incompatible_argument(
20382036
n,
20392037
m,
@@ -2155,13 +2153,11 @@ def check_overload_call(
21552153
else:
21562154
# There was no plausible match: give up
21572155
target = AnyType(TypeOfAny.from_error)
2158-
2159-
if not self.chk.should_suppress_optional_error(arg_types):
2160-
if not is_operator_method(callable_name):
2161-
code = None
2162-
else:
2163-
code = codes.OPERATOR
2164-
self.msg.no_variant_matches_arguments(callee, arg_types, context, code=code)
2156+
if not is_operator_method(callable_name):
2157+
code = None
2158+
else:
2159+
code = codes.OPERATOR
2160+
self.msg.no_variant_matches_arguments(callee, arg_types, context, code=code)
21652161

21662162
result = self.check_call(
21672163
target,

mypy/checkmember.py

-6
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,6 @@ def _analyze_member_access(
232232
elif isinstance(typ, DeletedType):
233233
mx.msg.deleted_as_rvalue(typ, mx.context)
234234
return AnyType(TypeOfAny.from_error)
235-
if mx.chk.should_suppress_optional_error([typ]):
236-
return AnyType(TypeOfAny.from_error)
237235
return report_missing_attribute(mx.original_type, typ, name, mx)
238236

239237

@@ -427,8 +425,6 @@ def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> T
427425
ret_type=literal_false,
428426
fallback=mx.named_type("builtins.function"),
429427
)
430-
elif mx.chk.should_suppress_optional_error([typ]):
431-
return AnyType(TypeOfAny.from_error)
432428
else:
433429
return _analyze_member_access(name, mx.named_type("builtins.object"), mx)
434430

@@ -545,8 +541,6 @@ def analyze_member_var_access(
545541
mx.msg.undefined_in_superclass(name, mx.context)
546542
return AnyType(TypeOfAny.from_error)
547543
else:
548-
if mx.chk and mx.chk.should_suppress_optional_error([itype]):
549-
return AnyType(TypeOfAny.from_error)
550544
return report_missing_attribute(mx.original_type, itype, name, mx)
551545

552546

mypy/config_parser.py

-2
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ def check_follow_imports(choice: str) -> str:
143143
# types.
144144
ini_config_types: Final[dict[str, _INI_PARSER_CALLABLE]] = {
145145
"python_version": parse_version,
146-
"strict_optional_whitelist": lambda s: s.split(),
147146
"custom_typing_module": str,
148147
"custom_typeshed_dir": expand_path,
149148
"mypy_path": lambda s: [expand_path(p.strip()) for p in re.split("[,:]", s)],
@@ -172,7 +171,6 @@ def check_follow_imports(choice: str) -> str:
172171
toml_config_types.update(
173172
{
174173
"python_version": parse_version,
175-
"strict_optional_whitelist": try_split,
176174
"mypy_path": lambda s: [expand_path(p) for p in try_split(s, "[,:]")],
177175
"files": lambda s: split_and_match_files_list(try_split(s)),
178176
"follow_imports": lambda s: check_follow_imports(str(s)),

mypy/main.py

-6
Original file line numberDiff line numberDiff line change
@@ -733,9 +733,6 @@ def add_invertible_flag(
733733
dest="strict_optional",
734734
help="Disable strict Optional checks (inverse: --strict-optional)",
735735
)
736-
none_group.add_argument(
737-
"--strict-optional-whitelist", metavar="GLOB", nargs="*", help=argparse.SUPPRESS
738-
)
739736

740737
lint_group = parser.add_argument_group(
741738
title="Configuring warnings",
@@ -1268,9 +1265,6 @@ def set_strict_flags() -> None:
12681265
options.disabled_error_codes -= options.enabled_error_codes
12691266

12701267
# Set build flags.
1271-
if options.strict_optional_whitelist is not None:
1272-
# TODO: Deprecate, then kill this flag
1273-
options.strict_optional = True
12741268
if special_opts.find_occurrences:
12751269
state.find_occurrences = special_opts.find_occurrences.split(".")
12761270
assert state.find_occurrences is not None

mypy/options.py

-9
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ class BuildType:
4747
"local_partial_types",
4848
"mypyc",
4949
"no_implicit_optional",
50-
"show_none_errors",
5150
"strict_concatenate",
5251
"strict_equality",
5352
"strict_optional",
54-
"strict_optional_whitelist",
5553
"warn_no_return",
5654
"warn_return_any",
5755
"warn_unreachable",
@@ -162,13 +160,6 @@ def __init__(self) -> None:
162160
self.color_output = True
163161
self.error_summary = True
164162

165-
# Files in which to allow strict-Optional related errors
166-
# TODO: Kill this in favor of show_none_errors
167-
self.strict_optional_whitelist: list[str] | None = None
168-
169-
# Alternate way to show/hide strict-None-checking related errors
170-
self.show_none_errors = True
171-
172163
# Don't assume arguments with default values of None are Optional
173164
self.no_implicit_optional = False
174165

test-data/unit/check-basic.test

-9
Original file line numberDiff line numberDiff line change
@@ -391,15 +391,6 @@ b = none.__bool__()
391391
reveal_type(b) # N: Revealed type is "Literal[False]"
392392
[builtins fixtures/bool.pyi]
393393

394-
[case testNoneHasBoolShowNoneErrorsFalse]
395-
none = None
396-
b = none.__bool__()
397-
reveal_type(b) # N: Revealed type is "Literal[False]"
398-
[builtins fixtures/bool.pyi]
399-
[file mypy.ini]
400-
\[mypy]
401-
show_none_errors = False
402-
403394
[case testAssignmentInvariantNoteForList]
404395
from typing import List
405396
x: List[int]

test-data/unit/check-optional.test

-52
Original file line numberDiff line numberDiff line change
@@ -396,58 +396,6 @@ reveal_type(None if bool() else 0) # N: Revealed type is "Union[Literal[0]?, No
396396
reveal_type([0, None, 0]) # N: Revealed type is "builtins.list[Union[builtins.int, None]]"
397397
[builtins fixtures/list.pyi]
398398

399-
[case testOptionalWhitelistSuppressesOptionalErrors]
400-
# flags: --strict-optional-whitelist
401-
import a
402-
import b
403-
[file a.py]
404-
from typing import Optional
405-
x = None # type: Optional[str]
406-
x + "foo"
407-
408-
[file b.py]
409-
from typing import Optional
410-
x = None # type: Optional[int]
411-
x + 1
412-
413-
[builtins fixtures/primitives.pyi]
414-
415-
[case testOptionalWhitelistPermitsOtherErrors]
416-
# flags: --strict-optional-whitelist
417-
import a
418-
import b
419-
[file a.py]
420-
from typing import Optional
421-
x = None # type: Optional[str]
422-
x + "foo"
423-
424-
[file b.py]
425-
from typing import Optional
426-
x = None # type: Optional[int]
427-
x + 1
428-
1 + "foo"
429-
[builtins fixtures/primitives.pyi]
430-
[out]
431-
tmp/b.py:4: error: Unsupported operand types for + ("int" and "str")
432-
433-
[case testOptionalWhitelistPermitsWhitelistedFiles]
434-
# flags: --strict-optional-whitelist **/a.py
435-
import a
436-
import b
437-
[file a.py]
438-
from typing import Optional
439-
x = None # type: Optional[str]
440-
x + "foo"
441-
442-
[file b.py]
443-
from typing import Optional
444-
x = None # type: Optional[int]
445-
x + 1
446-
[builtins fixtures/primitives.pyi]
447-
[out]
448-
tmp/a.py:3: error: Unsupported left operand type for + ("None")
449-
tmp/a.py:3: note: Left operand is of type "Optional[str]"
450-
451399
[case testNoneContextInference]
452400
from typing import Dict, List
453401
def f() -> List[None]:

test-data/unit/check-overloading.test

+1-1
Original file line numberDiff line numberDiff line change
@@ -5986,10 +5986,10 @@ reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A"
59865986
if True:
59875987
@overload # E: Single overload definition, multiple required
59885988
def f3(x: A) -> A: ...
5989+
def f3(x): ...
59895990
if maybe_true: # E: Name "maybe_true" is not defined
59905991
@overload # E: Single overload definition, multiple required
59915992
def g3(x: B) -> B: ...
5992-
def f3(x): ...
59935993
reveal_type(f3(A())) # N: Revealed type is "__main__.A"
59945994

59955995
if True:

0 commit comments

Comments
 (0)