Skip to content

Commit 5b54c35

Browse files
Do not error on boolean operations on values typed as object (#388)
1 parent d2b8274 commit 5b54c35

File tree

3 files changed

+16
-8
lines changed

3 files changed

+16
-8
lines changed

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Do not error on boolean operations on values typed
6+
as `object` (#388)
57
- Support some imports from stub-only modules (#386)
68
- Support type evaluation functions in stubs (#386)
79
- Support `TypedDict` in stubs (#386)

pyanalyze/boolability.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def _get_boolability_no_mvv(value: Value) -> Boolability:
142142
return Boolability.value_always_true_mutable
143143
else:
144144
return Boolability.value_always_false_mutable
145-
type_boolability = _get_type_boolability(type(value.val))
145+
type_boolability = _get_type_boolability(type(value.val), is_exact=True)
146146
if boolean_value:
147147
if type_boolability is Boolability.boolable:
148148
return Boolability.value_always_true
@@ -169,7 +169,11 @@ def _get_boolability_no_mvv(value: Value) -> Boolability:
169169
assert False, f"unhandled value {value!r}"
170170

171171

172-
def _get_type_boolability(typ: type) -> Boolability:
172+
def _get_type_boolability(typ: type, *, is_exact: bool = False) -> Boolability:
173+
# Special-case object as boolable because it could easily be a subtype
174+
# that does support __bool__.
175+
if typ is object and not is_exact:
176+
return Boolability.boolable
173177
if safe_hasattr(typ, "__len__"):
174178
return Boolability.boolable
175179
dunder_bool = safe_getattr(typ, "__bool__", None)

pyanalyze/test_boolability.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def test_get_boolability() -> None:
8686
# TypedValue
8787
assert Boolability.boolable == get_boolability(TypedValue(HasLen))
8888
assert Boolability.erroring_bool == get_boolability(future)
89-
assert Boolability.type_always_true == get_boolability(TypedValue(object))
89+
assert Boolability.boolable == get_boolability(TypedValue(object))
9090
assert Boolability.boolable == get_boolability(TypedValue(int))
9191

9292
# MultiValuedValue and AnnotatedValue
@@ -166,12 +166,14 @@ def __len__(self):
166166

167167
@assert_passes()
168168
def test_object():
169+
obj = object()
170+
169171
def capybara():
170-
True if object() else False # E: type_always_true
171-
object() and False # E: type_always_true
172-
[] and object() and False # E: type_always_true
173-
object() or True # E: type_always_true
174-
not object() # E: type_always_true
172+
True if obj else False # E: type_always_true
173+
obj and False # E: type_always_true
174+
[] and obj and False # E: type_always_true
175+
obj or True # E: type_always_true
176+
not obj # E: type_always_true
175177

176178
@assert_passes()
177179
def test_async_yield_or(self):

0 commit comments

Comments
 (0)