From 9a3d19e0d71f01dad0979b61cb8ace84af33dff8 Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 10:14:02 -0700 Subject: [PATCH 1/8] Better message for FUNCTION_ALWAYS_TRUE --- mypy/checker.py | 2 +- mypy/message_registry.py | 2 +- test-data/unit/check-errorcodes.test | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index f81cb7a1fd32..cc2652253473 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5273,7 +5273,7 @@ def format_expr_type() -> str: if isinstance(t, FunctionLike): self.fail( - message_registry.FUNCTION_ALWAYS_TRUE.format(format_type(t, self.options)), expr + message_registry.FUNCTION_ALWAYS_TRUE.format(expr.name), expr ) elif isinstance(t, UnionType): self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr) diff --git a/mypy/message_registry.py b/mypy/message_registry.py index b32edc06571a..6c76324067fd 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -154,7 +154,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: code=codes.TRUTHY_BOOL, ) FUNCTION_ALWAYS_TRUE: Final = ErrorMessage( - "Function {} could always be true in boolean context", code=codes.TRUTHY_FUNCTION + 'Function "{}" could always be true in boolean context', code=codes.TRUTHY_FUNCTION ) ITERABLE_ALWAYS_TRUE: Final = ErrorMessage( "{} which can always be true in boolean context. Consider using {} instead.", diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index fc498c9aa6c0..2d97b3ccec90 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -900,11 +900,11 @@ if any_or_object: # flags: --strict-optional def f(): pass -if f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-function] +if f: # E: Function "f" could always be true in boolean context [truthy-function] pass -if not f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-function] +if not f: # E: Function "f" could always be true in boolean context [truthy-function] pass -conditional_result = 'foo' if f else 'bar' # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-function] +conditional_result = 'foo' if f else 'bar' # E: Function "f" could always be true in boolean context [truthy-function] [case testTruthyIterable] # flags: --strict-optional --enable-error-code truthy-iterable From 37c902f8743a327fcf5e9ea726277ad5fb55d073 Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 10:17:53 -0700 Subject: [PATCH 2/8] Make lint and run formatters --- mypy/checker.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index cc2652253473..631208f7c9ed 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5272,9 +5272,7 @@ def format_expr_type() -> str: return f"Expression has type {typ}" if isinstance(t, FunctionLike): - self.fail( - message_registry.FUNCTION_ALWAYS_TRUE.format(expr.name), expr - ) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(expr.name), expr) elif isinstance(t, UnionType): self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr) elif isinstance(t, Instance) and t.type.fullname == "typing.Iterable": From c404fded0f854498c69bec630b8363f2aa2fb3dd Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 10:26:37 -0700 Subject: [PATCH 3/8] Update string formatting --- mypy/checker.py | 2 +- mypy/message_registry.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 631208f7c9ed..32c28ac686dd 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5272,7 +5272,7 @@ def format_expr_type() -> str: return f"Expression has type {typ}" if isinstance(t, FunctionLike): - self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(expr.name), expr) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(f'"{expr.name}"'), expr) elif isinstance(t, UnionType): self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr) elif isinstance(t, Instance) and t.type.fullname == "typing.Iterable": diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 6c76324067fd..35b949dae00a 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -154,7 +154,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: code=codes.TRUTHY_BOOL, ) FUNCTION_ALWAYS_TRUE: Final = ErrorMessage( - 'Function "{}" could always be true in boolean context', code=codes.TRUTHY_FUNCTION + 'Function {} could always be true in boolean context', code=codes.TRUTHY_FUNCTION ) ITERABLE_ALWAYS_TRUE: Final = ErrorMessage( "{} which can always be true in boolean context. Consider using {} instead.", From 23ab9748fe8e05f0074f32aa6a7443ddb00f8b8a Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 10:29:58 -0700 Subject: [PATCH 4/8] Removing accidental change --- mypy/message_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 35b949dae00a..b32edc06571a 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -154,7 +154,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: code=codes.TRUTHY_BOOL, ) FUNCTION_ALWAYS_TRUE: Final = ErrorMessage( - 'Function {} could always be true in boolean context', code=codes.TRUTHY_FUNCTION + "Function {} could always be true in boolean context", code=codes.TRUTHY_FUNCTION ) ITERABLE_ALWAYS_TRUE: Final = ErrorMessage( "{} which can always be true in boolean context. Consider using {} instead.", From 657d1954c880fd4d6515eecdb4fd454cdb8dae5f Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 13:55:04 -0700 Subject: [PATCH 5/8] Check expr has name --- mypy/checker.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 32c28ac686dd..a35aedb676ad 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5271,8 +5271,15 @@ def format_expr_type() -> str: else: return f"Expression has type {typ}" + def get_expr_name() -> str: + if hasattr(expr, "name"): + return str(expr.name) + else: + # return type if expr has no name + return format_type(t, self.options) + if isinstance(t, FunctionLike): - self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(f'"{expr.name}"'), expr) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(f'"{get_expr_name()}"'), expr) elif isinstance(t, UnionType): self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr) elif isinstance(t, Instance) and t.type.fullname == "typing.Iterable": From 623c6fef093655ba4c7ba3e803f62fff94a35f9d Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 14:56:56 -0700 Subject: [PATCH 6/8] Fix tests --- mypy/checker.py | 4 ++-- test-data/unit/check-flags.test | 4 ++-- test-data/unit/check-inline-config.test | 2 +- test-data/unit/check-python38.test | 2 +- test-data/unit/check-unreachable-code.test | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index a35aedb676ad..ebdc35b200aa 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5273,13 +5273,13 @@ def format_expr_type() -> str: def get_expr_name() -> str: if hasattr(expr, "name"): - return str(expr.name) + return f'"{str(expr.name)}"' else: # return type if expr has no name return format_type(t, self.options) if isinstance(t, FunctionLike): - self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(f'"{get_expr_name()}"'), expr) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(get_expr_name()), expr) elif isinstance(t, UnionType): self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr) elif isinstance(t, Instance) and t.type.fullname == "typing.Iterable": diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 244e728f3ab6..cd45ceb45834 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2101,12 +2101,12 @@ import tests.foo import bar [file bar.py] def foo() -> int: ... -if foo: ... # E: Function "Callable[[], int]" could always be true in boolean context +if foo: ... # E: Function "foo" could always be true in boolean context 42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead) [file tests/__init__.py] [file tests/foo.py] def foo() -> int: ... -if foo: ... # E: Function "Callable[[], int]" could always be true in boolean context +if foo: ... # E: Function "foo" could always be true in boolean context 42 + "no" # type: ignore [file mypy.ini] \[mypy] diff --git a/test-data/unit/check-inline-config.test b/test-data/unit/check-inline-config.test index db04536dd4f9..0cc2bd71270a 100644 --- a/test-data/unit/check-inline-config.test +++ b/test-data/unit/check-inline-config.test @@ -192,7 +192,7 @@ if foo: ... # mypy: enable-error-code="ignore-without-code" def foo() -> int: ... -if foo: ... # E: Function "Callable[[], int]" could always be true in boolean context +if foo: ... # E: Function "foo" could always be true in boolean context 42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead) [file tests/baz.py] diff --git a/test-data/unit/check-python38.test b/test-data/unit/check-python38.test index 4336cb4ca847..66c61febd4f8 100644 --- a/test-data/unit/check-python38.test +++ b/test-data/unit/check-python38.test @@ -310,7 +310,7 @@ def f(x: int = (c := 4)) -> int: z2: NT # E: Variable "NT" is not valid as a type \ # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases - if Alias := int: # E: Function "Type[int]" could always be true in boolean context + if Alias := int: # E: Function "Alias" could always be true in boolean context z3: Alias # E: Variable "Alias" is not valid as a type \ # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index a9e025632e24..b2fd44043435 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -936,7 +936,7 @@ class Case1: return False and self.missing() # E: Right operand of "and" is never evaluated def test2(self) -> bool: - return not self.property_decorator_missing and self.missing() # E: Function "Callable[[], bool]" could always be true in boolean context \ + return not self.property_decorator_missing and self.missing() # E: Function "property_decorator_missing" could always be true in boolean context \ # E: Right operand of "and" is never evaluated def property_decorator_missing(self) -> bool: From fda2a4ff401d3d883635584ca459af3d9708ec36 Mon Sep 17 00:00:00 2001 From: Theo Date: Fri, 5 May 2023 16:30:09 -0700 Subject: [PATCH 7/8] Fix walrus test --- test-data/unit/check-python38.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-data/unit/check-python38.test b/test-data/unit/check-python38.test index 66c61febd4f8..be99638226f6 100644 --- a/test-data/unit/check-python38.test +++ b/test-data/unit/check-python38.test @@ -310,7 +310,8 @@ def f(x: int = (c := 4)) -> int: z2: NT # E: Variable "NT" is not valid as a type \ # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases - if Alias := int: # E: Function "Alias" could always be true in boolean context + if Alias := int: # E: Function "Alias" could always be true in boolean context \ + # E: Function "int" could always be true in boolean context z3: Alias # E: Variable "Alias" is not valid as a type \ # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases From de8b7baef8418279fffaffbe6bf22abd841c7251 Mon Sep 17 00:00:00 2001 From: Theo Date: Sat, 13 May 2023 09:03:16 -0700 Subject: [PATCH 8/8] Use isinstance instead of hasatrr --- mypy/checker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index ebdc35b200aa..5136334d9e24 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5272,8 +5272,8 @@ def format_expr_type() -> str: return f"Expression has type {typ}" def get_expr_name() -> str: - if hasattr(expr, "name"): - return f'"{str(expr.name)}"' + if isinstance(expr, (NameExpr, MemberExpr)): + return f'"{expr.name}"' else: # return type if expr has no name return format_type(t, self.options)