Skip to content

Commit b2f1ed5

Browse files
committed
Enable strict optional by default
As an exception, tests still don't do this since there are hundreds of tests that would have to be updated. If tests explicitly define command line options, strict optional will be on by default -- basically command line options in tests default to `--no-strict-optional`. Fixes #359.
1 parent 3d94cae commit b2f1ed5

14 files changed

+186
-110
lines changed

docs/source/command_line.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ flag (or its long form ``--help``)::
2121
[--warn-unused-ignores] [--warn-unused-configs]
2222
[--show-error-context] [--no-implicit-optional] [--no-incremental]
2323
[--quick-and-dirty] [--cache-dir DIR] [--cache-fine-grained]
24-
[--skip-version-check] [--strict-optional]
24+
[--skip-version-check] [--no-strict-optional]
2525
[--strict-optional-whitelist [GLOB [GLOB ...]]]
2626
[--always-true NAME] [--always-false NAME] [--junit-xml JUNIT_XML]
2727
[--pdb] [--show-traceback] [--stats] [--inferstats]
@@ -298,11 +298,10 @@ Here are some more useful flags:
298298
- ``--ignore-missing-imports`` suppresses error messages about imports
299299
that cannot be resolved (see :ref:`follow-imports` for some examples).
300300

301-
- ``--strict-optional`` enables strict checking of ``Optional[...]``
302-
types and ``None`` values. Without this option, mypy doesn't
301+
- ``--no-strict-optional`` disables strict checking of ``Optional[...]``
302+
types and ``None`` values. With this option, mypy doesn't
303303
generally check the use of ``None`` values -- they are valid
304-
everywhere. See :ref:`strict_optional` for more about this feature.
305-
This flag will become the default in the near future.
304+
everywhere. See :ref:`no_strict_optional` for more about this feature.
306305

307306
- ``--disallow-untyped-defs`` reports an error whenever it encounters
308307
a function definition without type annotations.

docs/source/common_issues.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ flagged as an error.
5151
5252
If you don't know what types to add, you can use ``Any``, but beware:
5353

54-
- **One of the values involved has type ``Any``.** Extending the above
54+
- **One of the values involved has type Any.** Extending the above
5555
example, if we were to leave out the annotation for ``a``, we'd get
5656
no error:
5757

@@ -85,17 +85,16 @@ flagged as an error.
8585
clarity about the latter use ``--follow-imports=error``. You can
8686
read up about these and other useful flags in :ref:`command-line`.
8787

88-
- **A function annotated as returning a non-optional type returns ``None``
88+
- **A function annotated as returning a non-optional type returns None
8989
and mypy doesn't complain**.
9090

9191
.. code-block:: python
9292
9393
def foo() -> str:
9494
return None # No error!
9595
96-
By default, the ``None`` value is considered compatible with everything. See
97-
:ref:`optional` for details on strict optional checking, which allows mypy to
98-
check ``None`` values precisely, and will soon become default.
96+
You may have disabled strict optional checking (see
97+
:ref:`no_strict_optional` for more).
9998

10099
.. _silencing_checker:
101100

docs/source/config_file.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ The following global flags may only be set in the global section
9292
per-module sections in the config file that didn't match any
9393
files processed in the current run.
9494

95-
- ``strict_optional`` (Boolean, default False) enables experimental
96-
strict Optional checks.
97-
9895
- ``scripts_are_modules`` (Boolean, default False) makes script ``x``
9996
become module ``x`` instead of ``__main__``. This is useful when
10097
checking multiple scripts in a single run.
@@ -180,6 +177,11 @@ overridden by the pattern sections matching the module name.
180177
- ``almost_silent`` (Boolean, deprecated) equivalent to
181178
``follow_imports=skip``.
182179

180+
- ``strict_optional`` (Boolean, default True) enables or disables
181+
strict Optional checks. If False, mypy treats ``None`` as
182+
compatible with every type. This was False by default in mypy
183+
versions earlier than 0.600.
184+
183185
- ``disallow_any_unimported`` (Boolean, default false) disallows usage of types that come
184186
from unfollowed imports (such types become aliases for ``Any``).
185187

docs/source/kinds_of_types.rst

Lines changed: 152 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -345,50 +345,176 @@ narrow down the type to a specific type:
345345
f('x') # OK
346346
f(1.1) # Error
347347
348-
.. _optional:
348+
.. _strict_optional:
349349

350-
The type of None and optional types
351-
***********************************
350+
Optional types and the None type
351+
********************************
352352

353-
Mypy treats the type of ``None`` as special. ``None`` is a valid value
354-
for every type, which resembles ``null`` in Java. Unlike Java, mypy
355-
doesn't treat primitives types
356-
specially: ``None`` is also valid for primitive types such as ``int``
357-
and ``float``.
353+
You can use the ``Optional`` type modifier to define a type variant
354+
that includes ``None``, such as ``Optional[int]``:
358355

359-
.. note::
356+
.. code-block:: python
357+
358+
from typing import Optional
359+
360+
def f() -> Optional[int]:
361+
return None # OK
362+
363+
def g() -> int:
364+
...
365+
return None # Error: None not compatible with int
366+
367+
You can equivalently use ``Union[str, None]`` -- but ``Optional`` is
368+
shorter and more idiomatic. In this case ``None`` is a type with only
369+
one value, ``None``. Most operations will not be allowed on unguarded
370+
``None`` or ``Optional`` values:
371+
372+
.. code-block:: python
360373
361-
See :ref:`strict_optional` for an experimental mode which allows
362-
mypy to check ``None`` values precisely.
374+
def my_inc(x: Optional[int]) -> int:
375+
return x + 1 # Error: Cannot add None and int
376+
377+
Instead, an explicit ``None`` check is required. Mypy has
378+
powerful type inference that lets you use regular Python
379+
idioms to guard against ``None`` values. For example, mypy
380+
recognizes ``is None`` checks:
381+
382+
.. code-block:: python
383+
384+
def my_inc(x: Optional[int]) -> int:
385+
if x is None:
386+
return 0
387+
else:
388+
# The inferred type of x is just int here.
389+
return x + 1
390+
391+
Mypy will infer the type of ``x`` to be ``int`` in the else block due to the
392+
check against ``None`` in the if condition.
393+
394+
Other supported checks for guarding against a ``None`` value include ``if x is None``,
395+
``if x`` and ``if not x``. Additionally, mypy understands ``None`` checks within
396+
logical expressions:
397+
398+
.. code-block:: python
399+
400+
def concat(x: Optional[str], y: Optional[str]) -> Optional[str]:
401+
if x and y:
402+
# Both x and y are not None here
403+
return x + y
404+
else:
405+
return None
406+
407+
Sometimes mypy doesn't realize that a value is never ``None``. This notably
408+
happens when a class instance can exist in a partially defined state,
409+
where some attribute is initialized to ``None`` during object
410+
construction, but a method assumes that the attribute is no longer ``None``. Mypy
411+
will complain about the possible ``None`` value. You can use
412+
``assert x is not None`` to work around this:
413+
414+
.. code-block:: python
415+
416+
class Resource:
417+
path: Optional[str] = None
418+
419+
def initialize(self, path: str) -> None:
420+
self.path = path
421+
422+
def read(self) -> str:
423+
# We require that the object has been initizlied.
424+
assert self.path is not None
425+
with open(self.path) as f: # OK
426+
return f.read()
427+
428+
r = Resource()
429+
r.initialize('/foo/bar')
430+
r.read()
363431
364432
When initializing a variable as ``None``, ``None`` is usually an
365433
empty place-holder value, and the actual value has a different type.
366-
This is why you need to annotate an attribute in a case like this:
434+
This is why you need to annotate an attribute in a cases like the class
435+
``Resource`` above:
367436

368437
.. code-block:: python
369438
370-
class A:
439+
class Resource:
440+
path: Optional[str] = None
441+
...
442+
443+
This also works for attributes defined within methods:
444+
445+
.. code-block:: python
446+
447+
class Counter:
371448
def __init__(self) -> None:
372-
self.count = None # type: int
449+
self.count: Optional[int] = None
450+
451+
As a special case, you can use a non-optional type when initializing an
452+
attribute to ``None`` inside a class body *and* using a type comment,
453+
since when using a type comment, an initializer is syntacticaly required,
454+
and ``None`` is used as a dummy, placeholder initializer:
373455

374-
Mypy will complain if you omit the type annotation, as it wouldn't be
375-
able to infer a non-trivial type for the ``count`` attribute
376-
otherwise.
456+
.. code-block:: python
457+
458+
from typing import List
459+
460+
class Container:
461+
items = None # type: List[str] # OK (only with type comment)
377462
378463
Mypy generally uses the first assignment to a variable to
379464
infer the type of the variable. However, if you assign both a ``None``
380-
value and a non-``None`` value in the same scope, mypy can often do
381-
the right thing:
465+
value and a non-``None`` value in the same scope, mypy can usually do
466+
the right thing without an annotation:
382467

383468
.. code-block:: python
384469
385470
def f(i: int) -> None:
386-
n = None # Inferred type int because of the assignment below
471+
n = None # Inferred type Optional[int] because of the assignment below
387472
if i > 0:
388473
n = i
389474
...
390475
391-
Often it's useful to know whether a variable can be
476+
.. note::
477+
478+
``None`` is also used as the return type for functions that don't
479+
return a value, i.e. that implicitly return ``None``. (Mypy doesn't
480+
use ``NoneType`` for this, since it would
481+
look awkward, even though that is the real name of the type of ``None``
482+
-- try ``type(None)`` in the interactive interpreter to see for yourself.)
483+
484+
.. note::
485+
486+
``Optional[...]`` *does not* mean a function argument with a default value.
487+
However, if the default value of an argument is ``None``, you can use
488+
an optional type for the argument.
489+
490+
.. _no_strict_optional:
491+
492+
Disabling strict None checking
493+
******************************
494+
495+
Mypy also has an option to treat ``None`` as a valid value for every
496+
type (in case you know Java, it's useful to think of it as similar to
497+
the Java ``null``). In this mode ``None`` is also valid for primitive
498+
types such as ``int`` and ``float``.
499+
500+
The mode is enabled through the ``--no-strict-optional`` command-line
501+
option. It will cause mypy to silently accept some buggy code, such as
502+
this example, so it's not recommended if you can avoid it:
503+
504+
.. code-block:: python
505+
506+
def inc(x: int) -> int:
507+
return x + 1
508+
509+
x = inc(None) # No error reported by mypy!
510+
511+
In mypy versions before 0.600 this was the default mode, and if you
512+
recently upgraded to a more recent mypy version, you can enable this
513+
option for backward compatibility, if you don't want to introduce
514+
optional types to your codebase yet. Making code "optional clean"
515+
can take some work!
516+
517+
Often it's still useful to document whether a variable can be
392518
``None``. For example, this function accepts a ``None`` argument,
393519
but it's not obvious from its signature:
394520

@@ -403,8 +529,9 @@ but it's not obvious from its signature:
403529
print(greeting('Python')) # Okay!
404530
print(greeting(None)) # Also okay!
405531
406-
Mypy lets you use ``Optional[t]`` to document that ``None`` is a
407-
valid argument type:
532+
You can still use ``Optional[t]`` to document that ``None`` is a
533+
valid argument type, even if strict ``None`` checking is not
534+
enabled:
408535

409536
.. code-block:: python
410537
@@ -418,66 +545,8 @@ valid argument type:
418545
419546
Mypy treats this as semantically equivalent to the previous example,
420547
since ``None`` is implicitly valid for any type, but it's much more
421-
useful for a programmer who is reading the code. You can equivalently
422-
use ``Union[str, None]``, but ``Optional`` is shorter and more
423-
idiomatic.
424-
425-
.. note::
426-
427-
``None`` is also used as the return type for functions that don't
428-
return a value, i.e. that implicitly return ``None``. Mypy doesn't
429-
use ``NoneType`` for this, since it would
430-
look awkward, even though that is the real name of the type of ``None``
431-
(try ``type(None)`` in the interactive interpreter to see for yourself).
432-
433-
.. _strict_optional:
434-
435-
Strict optional type and None checking
436-
***************************************************
437-
438-
Currently, ``None`` is a valid value for each type, similar to
439-
``null`` or ``NULL`` in many languages. However, you can use the
440-
``--strict-optional`` command line option
441-
(which will become the default in the near future)
442-
to tell mypy that types should not include ``None``
443-
by default. The ``Optional`` type modifier is then used to define
444-
a type variant that includes ``None``, such as ``Optional[int]``:
445-
446-
.. code-block:: python
447-
448-
from typing import Optional
449-
450-
def f() -> Optional[int]:
451-
return None # OK
452-
453-
def g() -> int:
454-
...
455-
return None # Error: None not compatible with int
456-
457-
Also, most operations will not be allowed on unguarded ``None``
458-
or ``Optional`` values:
459-
460-
.. code-block:: python
461-
462-
def f(x: Optional[int]) -> int:
463-
return x + 1 # Error: Cannot add None and int
464-
465-
Instead, an explicit ``None`` check is required. Mypy has
466-
powerful type inference that lets you use regular Python
467-
idioms to guard against ``None`` values. For example, mypy
468-
recognizes ``is None`` checks:
469-
470-
.. code-block:: python
471-
472-
def f(x: Optional[int]) -> int:
473-
if x is None:
474-
return 0
475-
else:
476-
# The inferred type of x is just int here.
477-
return x + 1
478-
479-
Mypy will infer the type of ``x`` to be ``int`` in the else block due to the
480-
check against ``None`` in the if condition.
548+
useful for a programmer who is reading the code. This also makes
549+
it easier to migrate to strict ``None`` checking in the future.
481550

482551
.. _noreturn:
483552

docs/source/revision_history.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ List of major changes:
225225
- July 2016
226226
* Publish ``mypy-lang`` version 0.4.3 on PyPI.
227227

228-
* Add :ref:`strict_optional`.
228+
* Add ``--strict-optional``.
229229

230230
* Add :ref:`multi_line_annotation`.
231231

mypy/main.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,10 @@ def add_invertible_flag(flag: str,
424424
help="include fine-grained dependency information in the cache")
425425
parser.add_argument('--skip-version-check', action='store_true',
426426
help="allow using cache written by older mypy version")
427-
add_invertible_flag('--strict-optional', default=False, strict_flag=True,
428-
help="enable experimental strict Optional checks")
427+
parser.add_argument('--strict-optional', action='store_true',
428+
help=argparse.SUPPRESS)
429+
parser.add_argument('--no-strict-optional', action='store_false', dest='strict_optional',
430+
help="disable strict Optional checks (inverse: --no-strict-optional)")
429431
parser.add_argument('--strict-optional-whitelist', metavar='GLOB', nargs='*',
430432
help="suppress strict Optional errors in all but the provided files "
431433
"(experimental -- read documentation before using!). "

mypy/options.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def __init__(self) -> None:
120120
self.strict_boolean = False
121121

122122
# Apply strict None checking
123-
self.strict_optional = False
123+
self.strict_optional = True
124124

125125
# Show "note: In function "foo":" messages.
126126
self.show_error_context = False

mypy/test/helpers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ def parse_options(program_text: str, testcase: DataDrivenTestCase,
339339
raise RuntimeError('Specifying targets via the flags pragma is not supported.')
340340
else:
341341
options = Options()
342+
# TODO: Enable strict optional in test cases by default (requires *many* test case changes)
343+
options.strict_optional = False
342344

343345
# Allow custom python version to override testcase_pyversion
344346
if (not flag_list or

0 commit comments

Comments
 (0)