Skip to content

Commit 2849e58

Browse files
committed
Add --strict-bool flag to prohib treating bool as int
1 parent 6069718 commit 2849e58

File tree

5 files changed

+74
-0
lines changed

5 files changed

+74
-0
lines changed

docs/source/command_line.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,26 @@ of the above sections.
642642
643643
assert text is not None # OK, check against None is allowed as a special case.
644644
645+
.. option:: --strict-bool
646+
647+
By default ``bool`` values are treated as subtypes of ``int``,
648+
just like in runtime:
649+
650+
.. code-block:: python
651+
652+
>>> bool.__mro__
653+
(<class 'bool'>, <class 'int'>, <class 'object'>)
654+
655+
While it will work in runtime,
656+
some cases might require a little bit more strictness.
657+
With this flag enabled, you will get the following error:
658+
659+
.. code-block:: python
660+
661+
def requires_int(arg: int) -> None: ...
662+
663+
requires_int(5 > 0) # Error: Argument 1 has incompatible type "bool"; expected "int"
664+
645665
.. option:: --extra-checks
646666

647667
This flag enables additional checks that are technically correct but may be

mypy/main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,14 @@ def add_invertible_flag(
843843
group=strictness_group,
844844
)
845845

846+
add_invertible_flag(
847+
"--strict-bool",
848+
default=False,
849+
strict_flag=True,
850+
help="Prohib to treat bool as int",
851+
group=strictness_group,
852+
)
853+
846854
add_invertible_flag(
847855
"--extra-checks",
848856
default=False,

mypy/options.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class BuildType:
5050
"mypyc",
5151
"strict_concatenate",
5252
"strict_equality",
53+
"strict_bool",
5354
"strict_optional",
5455
"warn_no_return",
5556
"warn_return_any",
@@ -208,6 +209,10 @@ def __init__(self) -> None:
208209
# This makes 1 == '1', 1 in ['1'], and 1 is '1' errors.
209210
self.strict_equality = False
210211

212+
# Prohibit to treat `bool` as `int` in subtyping contexts.
213+
# This makes `def a(b: int): ...; a(True)` an error.
214+
self.strict_bool = False
215+
211216
# Deprecated, use extra_checks instead.
212217
self.strict_concatenate = False
213218

mypy/subtypes.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,13 @@ def visit_instance(self, left: Instance) -> bool:
512512
if left.type.alt_promote and left.type.alt_promote.type is right.type:
513513
return True
514514
rname = right.type.fullname
515+
if (
516+
self.options
517+
and self.options.strict_bool
518+
and left.type.fullname == "builtins.bool"
519+
and rname == "builtins.int"
520+
):
521+
return False
515522
# Always try a nominal check if possible,
516523
# there might be errors that a user wants to silence *once*.
517524
# NamedTuples are a special case, because `NamedTuple` is not listed

test-data/unit/check-flags.test

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,3 +2284,37 @@ class C(Generic[T]): ...
22842284

22852285
A = Union[C, List] # OK
22862286
[builtins fixtures/list.pyi]
2287+
2288+
[case testStrictBool]
2289+
# flags: --strict-bool --show-error-codes
2290+
from typing import List, Union
2291+
2292+
def a(x: int): ...
2293+
a(True) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2294+
a(False) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2295+
2296+
bl: bool
2297+
a(bl) # E: Argument 1 to "a" has incompatible type "bool"; expected "int" [arg-type]
2298+
2299+
def b() -> int:
2300+
return bl # E: Incompatible return value type (got "bool", expected "int") [return-value]
2301+
2302+
c: List[int] = [
2303+
True, # E: List item 0 has incompatible type "bool"; expected "int" [list-item]
2304+
False, # E: List item 1 has incompatible type "bool"; expected "int" [list-item]
2305+
bl, # E: List item 2 has incompatible type "bool"; expected "int" [list-item]
2306+
]
2307+
2308+
# OK:
2309+
def d(x: Union[int, bool], y: bool): ...
2310+
d(1, True)
2311+
d(True, False)
2312+
d(bl, bl)
2313+
[builtins fixtures/list.pyi]
2314+
2315+
[case testStrictBoolWithStrictFlag]
2316+
# flags: --strict
2317+
2318+
def a(x: int) -> None: ...
2319+
b: bool
2320+
a(b) # E: Argument 1 to "a" has incompatible type "bool"; expected "int"

0 commit comments

Comments
 (0)