Skip to content

Commit

Permalink
Suggest codemod for --no-implicit-optional (#13747)
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja committed Sep 29, 2022
1 parent e898652 commit 3015abf
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
24 changes: 22 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1262,13 +1262,27 @@ def check_default_args(self, item: FuncItem, body_is_trivial: bool) -> None:
msg += f"tuple argument {name[12:]}"
else:
msg += f'argument "{name}"'
if (
not self.options.implicit_optional
and isinstance(arg.initializer, NameExpr)
and arg.initializer.fullname == "builtins.None"
):
notes = [
"PEP 484 prohibits implicit Optional. "
"Accordingly, mypy has changed its default to no_implicit_optional=True",
"Use https://github.com/hauntsaninja/no_implicit_optional to automatically "
"upgrade your codebase",
]
else:
notes = None
self.check_simple_assignment(
arg.variable.type,
arg.initializer,
context=arg.initializer,
msg=ErrorMessage(msg, code=codes.ASSIGNMENT),
lvalue_name="argument",
rvalue_name="default",
notes=notes,
)

def is_forward_op_method(self, method_name: str) -> bool:
Expand Down Expand Up @@ -3739,6 +3753,8 @@ def check_simple_assignment(
msg: ErrorMessage = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
lvalue_name: str = "variable",
rvalue_name: str = "expression",
*,
notes: list[str] | None = None,
) -> Type:
if self.is_stub and isinstance(rvalue, EllipsisExpr):
# '...' is always a valid initializer in a stub.
Expand All @@ -3763,6 +3779,7 @@ def check_simple_assignment(
msg,
f"{rvalue_name} has type",
f"{lvalue_name} has type",
notes=notes,
)
return rvalue_type

Expand Down Expand Up @@ -5666,6 +5683,7 @@ def check_subtype(
subtype_label: str | None = None,
supertype_label: str | None = None,
*,
notes: list[str] | None = None,
code: ErrorCode | None = None,
outer_context: Context | None = None,
) -> bool:
Expand All @@ -5681,6 +5699,7 @@ def check_subtype(
subtype_label: str | None = None,
supertype_label: str | None = None,
*,
notes: list[str] | None = None,
outer_context: Context | None = None,
) -> bool:
...
Expand All @@ -5694,6 +5713,7 @@ def check_subtype(
subtype_label: str | None = None,
supertype_label: str | None = None,
*,
notes: list[str] | None = None,
code: ErrorCode | None = None,
outer_context: Context | None = None,
) -> bool:
Expand All @@ -5714,7 +5734,7 @@ def check_subtype(
return False
extra_info: list[str] = []
note_msg = ""
notes: list[str] = []
notes = notes or []
if subtype_label is not None or supertype_label is not None:
subtype_str, supertype_str = format_type_distinctly(orig_subtype, orig_supertype)
if subtype_label is not None:
Expand All @@ -5725,7 +5745,7 @@ def check_subtype(
outer_context or context, subtype, supertype, supertype_str
)
if isinstance(subtype, Instance) and isinstance(supertype, Instance):
notes = append_invariance_notes([], subtype, supertype)
notes = append_invariance_notes(notes, subtype, supertype)
if extra_info:
msg = msg.with_additional_msg(" (" + ", ".join(extra_info) + ")")

Expand Down
8 changes: 6 additions & 2 deletions test-data/unit/check-optional.test
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ f(None)

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

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

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

0 comments on commit 3015abf

Please sign in to comment.