Skip to content

Commit 027c58a

Browse files
authored
Use --no-implicit-optional by default (#13401)
Fixes #9091 This brings us in line with the PEP 484 updates in 2018
1 parent ab3b98f commit 027c58a

16 files changed

+44
-44
lines changed

Diff for: docs/source/command_line.rst

+7-13
Original file line numberDiff line numberDiff line change
@@ -390,29 +390,23 @@ None and Optional handling
390390
The following flags adjust how mypy handles values of type ``None``.
391391
For more details, see :ref:`no_strict_optional`.
392392

393-
.. _no-implicit-optional:
393+
.. _implicit-optional:
394394

395-
.. option:: --no-implicit-optional
395+
.. option:: --implicit-optional
396396

397-
This flag causes mypy to stop treating arguments with a ``None``
397+
This flag causes mypy to treat arguments with a ``None``
398398
default value as having an implicit :py:data:`~typing.Optional` type.
399399

400-
For example, by default mypy will assume that the ``x`` parameter
401-
is of type ``Optional[int]`` in the code snippet below since
402-
the default parameter is ``None``:
400+
For example, if this flag is set, mypy would assume that the ``x``
401+
parameter is actually of type ``Optional[int]`` in the code snippet below
402+
since the default parameter is ``None``:
403403

404404
.. code-block:: python
405405
406406
def foo(x: int = None) -> None:
407407
print(x)
408408
409-
If this flag is set, the above snippet will no longer type check:
410-
we must now explicitly indicate that the type is ``Optional[int]``:
411-
412-
.. code-block:: python
413-
414-
def foo(x: Optional[int] = None) -> None:
415-
print(x)
409+
**Note:** This was disabled by default starting in mypy 0.980.
416410

417411
.. option:: --no-strict-optional
418412

Diff for: docs/source/config_file.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -503,13 +503,15 @@ None and Optional handling
503503
For more information, see the :ref:`None and Optional handling <none-and-optional-handling>`
504504
section of the command line docs.
505505

506-
.. confval:: no_implicit_optional
506+
.. confval:: implicit_optional
507507

508508
:type: boolean
509509
:default: False
510510

511-
Changes the treatment of arguments with a default value of ``None`` by not implicitly
512-
making their type :py:data:`~typing.Optional`.
511+
Causes mypy to treat arguments with a ``None``
512+
default value as having an implicit :py:data:`~typing.Optional` type.
513+
514+
**Note:** This was True by default in mypy versions 0.980 and earlier.
513515

514516
.. confval:: strict_optional
515517

Diff for: docs/source/kinds_of_types.rst

+2-6
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,8 @@ case you should add an explicit ``Optional[...]`` annotation (or type comment).
388388
.. note::
389389

390390
``Optional[...]`` *does not* mean a function argument with a default value.
391-
However, if the default value of an argument is ``None``, you can use
392-
an optional type for the argument, but it's not enforced by default.
393-
You can use the :option:`--no-implicit-optional <mypy --no-implicit-optional>` command-line option to stop
394-
treating arguments with a ``None`` default value as having an implicit
395-
``Optional[...]`` type. It's possible that this will become the default
396-
behavior in the future.
391+
It simply means that ``None`` is a valid value for the argument. This is
392+
a common confusion because ``None`` is a common default value for arguments.
397393

398394
.. _alternative_union_syntax:
399395

Diff for: mypy/fastparse.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ def do_func_def(
10031003
return retval
10041004

10051005
def set_type_optional(self, type: Type | None, initializer: Expression | None) -> None:
1006-
if self.options.no_implicit_optional:
1006+
if not self.options.implicit_optional:
10071007
return
10081008
# Indicate that type should be wrapped in an Optional if arg is initialized to None.
10091009
optional = isinstance(initializer, NameExpr) and initializer.name == "None"

Diff for: mypy/main.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -720,10 +720,9 @@ def add_invertible_flag(
720720
"https://mypy.readthedocs.io/en/stable/kinds_of_types.html#no-strict-optional",
721721
)
722722
add_invertible_flag(
723-
"--no-implicit-optional",
723+
"--implicit-optional",
724724
default=False,
725-
strict_flag=True,
726-
help="Don't assume arguments with default values of None are Optional",
725+
help="Assume arguments with default values of None are Optional",
727726
group=none_group,
728727
)
729728
none_group.add_argument("--strict-optional", action="store_true", help=argparse.SUPPRESS)

Diff for: mypy/options.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ class BuildType:
3939
"disallow_untyped_defs",
4040
"enable_error_code",
4141
"enabled_error_codes",
42-
"follow_imports",
4342
"follow_imports_for_stubs",
43+
"follow_imports",
4444
"ignore_errors",
4545
"ignore_missing_imports",
46+
"implicit_optional",
4647
"implicit_reexport",
4748
"local_partial_types",
4849
"mypyc",
49-
"no_implicit_optional",
5050
"strict_concatenate",
5151
"strict_equality",
5252
"strict_optional",
@@ -162,8 +162,8 @@ def __init__(self) -> None:
162162
self.color_output = True
163163
self.error_summary = True
164164

165-
# Don't assume arguments with default values of None are Optional
166-
self.no_implicit_optional = False
165+
# Assume arguments with default values of None are Optional
166+
self.implicit_optional = False
167167

168168
# Don't re-export names unless they are imported with `from ... as ...`
169169
self.implicit_reexport = True

Diff for: test-data/unit/check-classes.test

+2-1
Original file line numberDiff line numberDiff line change
@@ -2979,8 +2979,9 @@ class B: pass
29792979

29802980

29812981
[case testConstructInstanceWith__new__]
2982+
from typing import Optional
29822983
class C:
2983-
def __new__(cls, foo: int = None) -> 'C':
2984+
def __new__(cls, foo: Optional[int] = None) -> 'C':
29842985
obj = object.__new__(cls)
29852986
return obj
29862987

Diff for: test-data/unit/check-fastparse.test

+2
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class C:
106106
[builtins fixtures/property.pyi]
107107

108108
[case testFastParsePerArgumentAnnotations]
109+
# flags: --implicit-optional
109110

110111
class A: pass
111112
class B: pass
@@ -130,6 +131,7 @@ def f(a, # type: A
130131
[out]
131132

132133
[case testFastParsePerArgumentAnnotationsWithReturn]
134+
# flags: --implicit-optional
133135

134136
class A: pass
135137
class B: pass

Diff for: test-data/unit/check-flags.test

+2
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ standard.f(None)
843843
[file mypy.ini]
844844
\[mypy]
845845
strict_optional = False
846+
implicit_optional = true
846847
\[mypy-optional]
847848
strict_optional = True
848849

@@ -862,6 +863,7 @@ standard.f(None)
862863
[file pyproject.toml]
863864
\[tool.mypy]
864865
strict_optional = false
866+
implicit_optional = true
865867
\[[tool.mypy.overrides]]
866868
module = 'optional'
867869
strict_optional = true

Diff for: test-data/unit/check-functions.test

+1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ if int():
465465

466466

467467
[case testCallingFunctionsWithDefaultArgumentValues]
468+
# flags: --implicit-optional --no-strict-optional
468469

469470
a, b = None, None # type: (A, B)
470471
if int():

Diff for: test-data/unit/check-kwargs.test

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class A: pass
2424
class B: pass
2525

2626
[case testOneOfSeveralOptionalKeywordArguments]
27+
# flags: --implicit-optional
2728
import typing
2829
def f(a: 'A' = None, b: 'B' = None, c: 'C' = None) -> None: pass
2930
f(a=A())
@@ -219,6 +220,7 @@ f(a, **b)
219220
[builtins fixtures/dict.pyi]
220221

221222
[case testKeywordArgAfterVarArgs]
223+
# flags: --implicit-optional
222224
import typing
223225
def f(*a: 'A', b: 'B' = None) -> None: pass
224226
f()
@@ -235,6 +237,7 @@ class B: pass
235237
[builtins fixtures/list.pyi]
236238

237239
[case testKeywordArgAfterVarArgsWithBothCallerAndCalleeVarArgs]
240+
# flags: --implicit-optional --no-strict-optional
238241
from typing import List
239242
def f(*a: 'A', b: 'B' = None) -> None: pass
240243
a = None # type: List[A]

Diff for: test-data/unit/check-optional.test

+2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def f(x: None) -> None: pass
127127
f(None)
128128

129129
[case testInferOptionalFromDefaultNone]
130+
# flags: --implicit-optional
130131
def f(x: int = None) -> None:
131132
x + 1 # E: Unsupported left operand type for + ("None") \
132133
# N: Left operand is of type "Optional[int]"
@@ -140,6 +141,7 @@ def f(x: int = None) -> None: # E: Incompatible default for argument "x" (defau
140141
[out]
141142

142143
[case testInferOptionalFromDefaultNoneComment]
144+
# flags: --implicit-optional
143145
def f(x=None):
144146
# type: (int) -> None
145147
x + 1 # E: Unsupported left operand type for + ("None") \

Diff for: test-data/unit/check-varargs.test

+7-10
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class C: pass
8282
[builtins fixtures/list.pyi]
8383

8484
[case testCallingVarArgsFunctionWithDefaultArgs]
85+
# flags: --implicit-optional --no-strict-optional
8586

8687
a = None # type: A
8788
b = None # type: B
@@ -388,12 +389,14 @@ class B(A): pass
388389
[builtins fixtures/list.pyi]
389390

390391
[case testCallerVarArgsAndDefaultArgs]
392+
# flags: --implicit-optional --no-strict-optional
391393

392394
a, b = None, None # type: (A, B)
393-
f(*()) # Fail
394-
f(a, *[a]) # Fail
395-
f(a, b, *[a]) # Fail
396-
f(*(a, a, b)) # Fail
395+
f(*()) # E: Too few arguments for "f"
396+
f(a, *[a]) # E: Argument 2 to "f" has incompatible type "*List[A]"; expected "Optional[B]" \
397+
# E: Argument 2 to "f" has incompatible type "*List[A]"; expected "B"
398+
f(a, b, *[a]) # E: Argument 3 to "f" has incompatible type "*List[A]"; expected "B"
399+
f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type "*Tuple[A, A, B]"; expected "Optional[B]"
397400
f(*(a,))
398401
f(*(a, b))
399402
f(*(a, b, b, b))
@@ -407,12 +410,6 @@ def f(a: 'A', b: 'B' = None, *c: 'B') -> None:
407410
class A: pass
408411
class B: pass
409412
[builtins fixtures/list.pyi]
410-
[out]
411-
main:3: error: Too few arguments for "f"
412-
main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "Optional[B]"
413-
main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "B"
414-
main:5: error: Argument 3 to "f" has incompatible type "*List[A]"; expected "B"
415-
main:6: error: Argument 1 to "f" has incompatible type "*Tuple[A, A, B]"; expected "Optional[B]"
416413

417414
[case testVarArgsAfterKeywordArgInCall1]
418415
# see: mypy issue #2729

Diff for: test-data/unit/fine-grained.test

+1-1
Original file line numberDiff line numberDiff line change
@@ -7942,7 +7942,7 @@ class Foo(a.I):
79427942
==
79437943

79447944
[case testImplicitOptionalRefresh1]
7945-
# flags: --strict-optional
7945+
# flags: --strict-optional --implicit-optional
79467946
from x import f
79477947
def foo(x: int = None) -> None:
79487948
f()

Diff for: test-data/unit/fixtures/tuple.pyi

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Builtins stub used in tuple-related test cases.
22

3-
from typing import Iterable, Iterator, TypeVar, Generic, Sequence, Any, overload, Tuple, Type
3+
from typing import Iterable, Iterator, TypeVar, Generic, Sequence, Optional, overload, Tuple, Type
44

55
T = TypeVar("T")
66
Tco = TypeVar('Tco', covariant=True)
@@ -47,6 +47,6 @@ class list(Sequence[T], Generic[T]):
4747

4848
def isinstance(x: object, t: type) -> bool: pass
4949

50-
def sum(iterable: Iterable[T], start: T = None) -> T: pass
50+
def sum(iterable: Iterable[T], start: Optional[T] = None) -> T: pass
5151

5252
class BaseException: pass

Diff for: test-data/unit/fixtures/typing-namedtuple.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Any = 0
44
overload = 0
55
Type = 0
66
Literal = 0
7+
Optional = 0
78

89
T_co = TypeVar('T_co', covariant=True)
910
KT = TypeVar('KT')

0 commit comments

Comments
 (0)