From d99807e66e33211dd1082ee6218b673538b6ddc1 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 7 Oct 2021 11:52:24 +0300 Subject: [PATCH 1/2] WIP: `None.__bool__` returns `Literal[False]`, refs #11287 --- mypy/checkmember.py | 3 ++- test-data/unit/check-basic.test | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 4fc96de039b0e..3d91798917a58 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -323,10 +323,11 @@ def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> T # In Python 2 "None" has exactly the same attributes as "object". Python 3 adds a single # extra attribute, "__bool__". if is_python_3 and name == '__bool__': + literal_false = LiteralType(False, fallback=mx.named_type('builtins.bool')) return CallableType(arg_types=[], arg_kinds=[], arg_names=[], - ret_type=mx.named_type('builtins.bool'), + ret_type=literal_false, fallback=mx.named_type('builtins.function')) else: return _analyze_member_access(name, mx.named_type('builtins.object'), mx) diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index 184c9e58ca586..d6b7b08021287 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -401,7 +401,7 @@ def foo( [case testNoneHasBool] none = None b = none.__bool__() -reveal_type(b) # N: Revealed type is "builtins.bool" +reveal_type(b) # N: Revealed type is "Literal[False]" [builtins fixtures/bool.pyi] [case testAssignmentInvariantNoteForList] From 1cfc73e38c27fa6438682b1d43157140be6658d1 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 7 Oct 2021 21:01:59 +0300 Subject: [PATCH 2/2] Adds support for `None.__bool__` when `show_none_errors = False` is set --- mypy/checkmember.py | 4 ++-- test-data/unit/check-basic.test | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 3d91798917a58..3579fda2e7f44 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -317,8 +317,6 @@ def analyze_union_member_access(name: str, typ: UnionType, mx: MemberContext) -> def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> Type: - if mx.chk.should_suppress_optional_error([typ]): - return AnyType(TypeOfAny.from_error) is_python_3 = mx.chk.options.python_version[0] >= 3 # In Python 2 "None" has exactly the same attributes as "object". Python 3 adds a single # extra attribute, "__bool__". @@ -329,6 +327,8 @@ def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> T arg_names=[], ret_type=literal_false, fallback=mx.named_type('builtins.function')) + elif mx.chk.should_suppress_optional_error([typ]): + return AnyType(TypeOfAny.from_error) else: return _analyze_member_access(name, mx.named_type('builtins.object'), mx) diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index d6b7b08021287..03dee485c8482 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -404,6 +404,15 @@ b = none.__bool__() reveal_type(b) # N: Revealed type is "Literal[False]" [builtins fixtures/bool.pyi] +[case testNoneHasBoolShowNoneErrorsFalse] +none = None +b = none.__bool__() +reveal_type(b) # N: Revealed type is "Literal[False]" +[builtins fixtures/bool.pyi] +[file mypy.ini] +\[mypy] +show_none_errors = False + [case testAssignmentInvariantNoteForList] from typing import List x: List[int]