Skip to content

Commit 3015abf

Browse files
authored
Suggest codemod for --no-implicit-optional (#13747)
1 parent e898652 commit 3015abf

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

mypy/checker.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,13 +1262,27 @@ def check_default_args(self, item: FuncItem, body_is_trivial: bool) -> None:
12621262
msg += f"tuple argument {name[12:]}"
12631263
else:
12641264
msg += f'argument "{name}"'
1265+
if (
1266+
not self.options.implicit_optional
1267+
and isinstance(arg.initializer, NameExpr)
1268+
and arg.initializer.fullname == "builtins.None"
1269+
):
1270+
notes = [
1271+
"PEP 484 prohibits implicit Optional. "
1272+
"Accordingly, mypy has changed its default to no_implicit_optional=True",
1273+
"Use https://github.com/hauntsaninja/no_implicit_optional to automatically "
1274+
"upgrade your codebase",
1275+
]
1276+
else:
1277+
notes = None
12651278
self.check_simple_assignment(
12661279
arg.variable.type,
12671280
arg.initializer,
12681281
context=arg.initializer,
12691282
msg=ErrorMessage(msg, code=codes.ASSIGNMENT),
12701283
lvalue_name="argument",
12711284
rvalue_name="default",
1285+
notes=notes,
12721286
)
12731287

12741288
def is_forward_op_method(self, method_name: str) -> bool:
@@ -3739,6 +3753,8 @@ def check_simple_assignment(
37393753
msg: ErrorMessage = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
37403754
lvalue_name: str = "variable",
37413755
rvalue_name: str = "expression",
3756+
*,
3757+
notes: list[str] | None = None,
37423758
) -> Type:
37433759
if self.is_stub and isinstance(rvalue, EllipsisExpr):
37443760
# '...' is always a valid initializer in a stub.
@@ -3763,6 +3779,7 @@ def check_simple_assignment(
37633779
msg,
37643780
f"{rvalue_name} has type",
37653781
f"{lvalue_name} has type",
3782+
notes=notes,
37663783
)
37673784
return rvalue_type
37683785

@@ -5666,6 +5683,7 @@ def check_subtype(
56665683
subtype_label: str | None = None,
56675684
supertype_label: str | None = None,
56685685
*,
5686+
notes: list[str] | None = None,
56695687
code: ErrorCode | None = None,
56705688
outer_context: Context | None = None,
56715689
) -> bool:
@@ -5681,6 +5699,7 @@ def check_subtype(
56815699
subtype_label: str | None = None,
56825700
supertype_label: str | None = None,
56835701
*,
5702+
notes: list[str] | None = None,
56845703
outer_context: Context | None = None,
56855704
) -> bool:
56865705
...
@@ -5694,6 +5713,7 @@ def check_subtype(
56945713
subtype_label: str | None = None,
56955714
supertype_label: str | None = None,
56965715
*,
5716+
notes: list[str] | None = None,
56975717
code: ErrorCode | None = None,
56985718
outer_context: Context | None = None,
56995719
) -> bool:
@@ -5714,7 +5734,7 @@ def check_subtype(
57145734
return False
57155735
extra_info: list[str] = []
57165736
note_msg = ""
5717-
notes: list[str] = []
5737+
notes = notes or []
57185738
if subtype_label is not None or supertype_label is not None:
57195739
subtype_str, supertype_str = format_type_distinctly(orig_subtype, orig_supertype)
57205740
if subtype_label is not None:
@@ -5725,7 +5745,7 @@ def check_subtype(
57255745
outer_context or context, subtype, supertype, supertype_str
57265746
)
57275747
if isinstance(subtype, Instance) and isinstance(supertype, Instance):
5728-
notes = append_invariance_notes([], subtype, supertype)
5748+
notes = append_invariance_notes(notes, subtype, supertype)
57295749
if extra_info:
57305750
msg = msg.with_additional_msg(" (" + ", ".join(extra_info) + ")")
57315751

test-data/unit/check-optional.test

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ f(None)
136136

137137
[case testNoInferOptionalFromDefaultNone]
138138
# flags: --no-implicit-optional
139-
def f(x: int = None) -> None: # E: Incompatible default for argument "x" (default has type "None", argument has type "int")
139+
def f(x: int = None) -> None: # E: Incompatible default for argument "x" (default has type "None", argument has type "int") \
140+
# N: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True \
141+
# N: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
140142
pass
141143
[out]
142144

@@ -151,7 +153,9 @@ f(None)
151153

152154
[case testNoInferOptionalFromDefaultNoneComment]
153155
# flags: --no-implicit-optional
154-
def f(x=None): # E: Incompatible default for argument "x" (default has type "None", argument has type "int")
156+
def f(x=None): # E: Incompatible default for argument "x" (default has type "None", argument has type "int") \
157+
# N: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True \
158+
# N: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
155159
# type: (int) -> None
156160
pass
157161
[out]

0 commit comments

Comments
 (0)