Replies: 6 comments 17 replies
-
|
This pattern has legitimate uses and is quite common in Python, so it's not a rule that could be enabled by default, even in strict mode. In general, I don't like adding rules that cannot be enabled by default in strict mode because they are difficult for pyright users to discover and therefore are rarely used. This situation is also not a type violation, which means that it's not obvious that it's a rule a type checker should be enforcing. There is a precedent for pyright supporting rules that are not type violations but do require type analysis (and are therefore difficult for linters to implement). These rules all involve cases where 1) there's a relatively low chance of a false positive and 2) a reasonably high likelihood of an actual bug. The This particular check doesn't seem to meet this bar. I'm not convinced that it represents a sufficiently common source of bugs to merit adding such a rule, but I could perhaps be persuaded with some additional evidence. For comparison, the typescript compiler (which is effectively a static type checker) does not provide an option like the one you're proposing, but eslint (which is more akin to a ruff) does. |
Beta Was this translation helpful? Give feedback.
-
|
I have a case where an API some functions return a direct when they actually meant: It feels unfortunate that pyright doesn't seem to have an option to warn about "truthy tuples", esp. as the type of this tuple is statically determined and known to always evaluate to True. Ruff has a rule for this (https://docs.astral.sh/ruff/rules/if-tuple/) but unfortunately it only works for literal values, as Ruff is not a type checker. |
Beta Was this translation helpful? Give feedback.
-
|
I'd support an optional rule to flag this sort of usage, but I'd like to reiterate that a 'fast and loose association with the truth' has been a part of python since its inception (for good or ill), and it can be a perfectly legitimate shorthand. E.g. regex usage: animal_pattern = re.compile(r"(?P<phrase>(?P<prefix>It's|This is an? )(?P<animal>\w+)!)")
animals: list[dict[str, str]] = []
phrase = "This is a walrus!"
if _animal_match := animal_pattern.match(phrase): # seems legit...
animals.append(_animal_match.groupdict())
if (_animal_match := animal_pattern.match(phrase)) is not None: # feels clunky and unnecessary...
animals.append(_animal_match.groupdict())Strict container truthiness might also encourage the introduction of bugs from simple type system frustration. For example, a frustrating or cryptic flag might lead to bad decisions like omitting the my_list: list[int]
if my_list and my_list[0] < 10:
my_list[0] += 10You'd want to be very explicit about why this rule exists and how to fix it in the error message. |
Beta Was this translation helpful? Give feedback.
-
|
A lack of such a check could lead to silent introduction of bugs during refactoring. Suppose I have the following code: def try_frobnicate() -> bool:
# ...
# elsewhere
success = try_frobnicate()
if success: # correct usage - success is a bool
# ...Then later I refactor it to provide more information: def try_frobnicate() -> Result[Success, Error]: # Result is Union[Ok, Err]
# ...
# elsewhere
success = try_frobnicate()
if success: # uh-oh, Err is truthy but no warning raised, hard to spot manually
# ...I think any codebase that takes type safety seriously will (or at least should) want to ban non-bool values from condition checks. I'm not sure if it is feasible at a linter level. |
Beta Was this translation helpful? Give feedback.
-
|
@erictraut – I remember you saying that you could revisit decisions to implement new rules if there is evidence of community demand (upvotes, comments). Could I ask what's your view on this rule now? It's among the top open discussions at the moment. Especially if, in addition to "upvotes", you also count "thumbs up" – which this discussion seems to have more relatively to others. Edit: I think a succinct, Pythonic justification for this rule could be that it prevents PEP 8 violations, which states:
|
Beta Was this translation helpful? Give feedback.
-
|
Just ran into a bug that this would have caught. I was refactoring some code and they had used an implicit bool coersion like this: During the refactoring I change the type of I'm surprised this isn't a rule already. It's a pretty common footgun in my experience, and very bad style so nobody should be writing code like this anyway (so IMO it should be enabled by default in strict mode). It's also difficult for tools like Pylint to implement because it requires precise type knowledge. Typescript has had this rule available for a long time. |
Beta Was this translation helpful? Give feedback.


Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I've started a discussion on this on Ruff's GitHub, but I'm also curious if this is something that Pyright might consider implementing.
I'd like to ban implicit truthy/falsy checks in our codebase, to avoid common bugs like this:
More details and broader rationale in this discussion: astral-sh/ruff#8757
@erictraut – what's you view on this? Does this feel like a rule Pyright might implement? (I would imagine it would be optional even in strict mode.)
On one hand it feels opinionated enough to be a linter rule, on the other hand I have a hunch it might be easier and more robust to implement in a type checker (feels a bit similar to e.g.
reportUnnecessaryComparison).Beta Was this translation helpful? Give feedback.
All reactions