Skip to content

Commit

Permalink
Add error-code for truthy-function (#13686)
Browse files Browse the repository at this point in the history
A separate error code for `truthy-function` so it can be enabled by default.

Closes #12621

Co-authored-by: Shantanu <[email protected]>
  • Loading branch information
cdce8p and hauntsaninja authored Oct 14, 2022
1 parent ea606b4 commit b3d94dc
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 17 deletions.
13 changes: 13 additions & 0 deletions docs/source/error_code_list2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,19 @@ except that attempting to invoke an undefined method (e.g. ``__len__``) results
while attempting to evaluate an object in boolean context without a concrete implementation results in a truthy value.


Check that function isn't used in boolean context [truthy-function]
-------------------------------------------------------------------

Functions will always evaluate to true in boolean contexts.

.. code-block:: python
def f():
...
if f: # Error: Function "Callable[[], Any]" could always be true in boolean context [truthy-function]
pass
.. _ignore-without-code:

Check that ``# type: ignore`` include an error code [ignore-without-code]
Expand Down
5 changes: 5 additions & 0 deletions mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ def __str__(self) -> str:
"General",
default_enabled=False,
)
TRUTHY_FUNCTION: Final[ErrorCode] = ErrorCode(
"truthy-function",
"Warn about function that always evaluate to true in boolean contexts",
"General",
)
NAME_MATCH: Final = ErrorCode(
"name-match", "Check that type definition has consistent naming", "General"
)
Expand Down
2 changes: 1 addition & 1 deletion mypy/message_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,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_BOOL
"Function {} could always be true in boolean context", code=codes.TRUTHY_FUNCTION
)
NOT_CALLABLE: Final = "{} not callable"
TYPE_MUST_BE_USED: Final = "Value of type {} must be used"
Expand Down
18 changes: 10 additions & 8 deletions test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -842,19 +842,21 @@ if bad_union: # E: "__main__.bad_union" has type "Union[Foo, object]" of which
if not bad_union: # E: "__main__.bad_union" has type "object" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
pass

def f():
pass
if f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool]
pass
if not f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool]
pass
conditional_result = 'foo' if f else 'bar' # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool]

lst: List[int] = []
if lst:
pass
[builtins fixtures/list.pyi]

[case testTruthyFunctions]
# flags: --strict-optional
def f():
pass
if f: # E: Function "Callable[[], Any]" 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]
pass
conditional_result = 'foo' if f else 'bar' # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-function]

[case testNoOverloadImplementation]
from typing import overload

Expand Down
7 changes: 5 additions & 2 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -6017,12 +6017,15 @@ tmp/m.py:2: error: Argument "age" to "foo" has incompatible type "str"; expected
[case testDisableEnableErrorCodesIncremental]
# flags: --disable-error-code truthy-bool
# flags2: --enable-error-code truthy-bool
def foo() -> int: ...
class Foo:
pass

foo = Foo()
if foo:
...
[out]
[out2]
main:4: error: Function "Callable[[], int]" could always be true in boolean context
main:7: error: "__main__.foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context

[case testModuleAsProtocolImplementationSerialize]
import m
Expand Down
14 changes: 10 additions & 4 deletions test-data/unit/check-inline-config.test
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,11 @@ main:1: error: Setting "strict" not supported in inline configuration: specify i
[case testInlineErrorCodes]
# flags: --strict-optional
# mypy: enable-error-code="ignore-without-code,truthy-bool"
class Foo:
pass

def foo() -> int: ...
if foo: ... # E: Function "Callable[[], int]" could always be true in boolean context
foo = Foo()
if foo: ... # E: "__main__.foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context
42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead)

[case testInlineErrorCodesOverrideConfig]
Expand All @@ -178,8 +180,10 @@ import tests.bar
import tests.baz
[file foo.py]
# mypy: disable-error-code="truthy-bool"
class Foo:
pass

def foo() -> int: ...
foo = Foo()
if foo: ...
42 + "no" # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[operator]" instead)

Expand All @@ -193,8 +197,10 @@ if foo: ... # E: Function "Callable[[], int]" could always be true in boolean c

[file tests/baz.py]
# mypy: disable-error-code="truthy-bool"
class Foo:
pass

def foo() -> int: ...
foo = Foo()
if foo: ...
42 + "no" # type: ignore

Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-python38.test
Original file line number Diff line number Diff line change
Expand Up @@ -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:
if Alias := int: # E: Function "Type[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

Expand Down
3 changes: 2 additions & 1 deletion test-data/unit/check-unreachable-code.test
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,8 @@ 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: Right operand of "and" is never evaluated
return not self.property_decorator_missing and self.missing() # E: Function "Callable[[], bool]" could always be true in boolean context \
# E: Right operand of "and" is never evaluated

def property_decorator_missing(self) -> bool:
return True
Expand Down

0 comments on commit b3d94dc

Please sign in to comment.