Skip to content

Commit f20c12f

Browse files
committed
Fix enum truthiness for StrEnum
Fixes python#18376
1 parent 7982761 commit f20c12f

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

mypy/typeops.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -651,16 +651,8 @@ def _remove_redundant_union_items(items: list[Type], keep_erased: bool) -> list[
651651
def _get_type_method_ret_type(t: Type, *, name: str) -> Type | None:
652652
t = get_proper_type(t)
653653

654-
# For Enum literals the ret_type can change based on the Enum
655-
# we need to check the type of the enum rather than the literal
656-
if isinstance(t, LiteralType) and t.is_enum_literal():
657-
t = t.fallback
658-
659654
if isinstance(t, Instance):
660655
sym = t.type.get(name)
661-
# Fallback to the metaclass for the lookup when necessary
662-
if not sym and (m := t.type.metaclass_type):
663-
sym = m.type.get(name)
664656
if sym:
665657
sym_type = get_proper_type(sym.type)
666658
if isinstance(sym_type, CallableType):
@@ -733,8 +725,9 @@ def false_only(t: Type) -> ProperType:
733725
if ret_type:
734726
if not ret_type.can_be_false:
735727
return UninhabitedType(line=t.line)
736-
elif isinstance(t, Instance) and t.type.is_final:
737-
return UninhabitedType(line=t.line)
728+
elif isinstance(t, Instance):
729+
if t.type.is_final or t.type.is_enum:
730+
return UninhabitedType(line=t.line)
738731

739732
new_t = copy_type(t)
740733
new_t.can_be_true = False

test-data/unit/check-enum.test

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,65 @@ def infer_truth(truth: Truth) -> None:
182182
# mypy: warn-unreachable
183183
import enum
184184
class E(enum.Enum):
185-
x = 0
186-
if not E.x:
187-
"noop"
185+
zero = 0
186+
one = 1
187+
188+
def print(s: str) -> None: ...
189+
190+
if E.zero:
191+
print("zero is true")
192+
if not E.zero:
193+
print("zero is false") # E: Statement is unreachable
194+
195+
if E.one:
196+
print("one is true")
197+
if not E.one:
198+
print("one is false") # E: Statement is unreachable
188199
[builtins fixtures/tuple.pyi]
189-
[out]
190-
main:6: error: Statement is unreachable
191200

192201
[case testEnumTruthynessCustomDunderBool]
193202
# mypy: warn-unreachable
194203
import enum
195204
from typing_extensions import Literal
196205
class E(enum.Enum):
197-
x = 0
206+
zero = 0
207+
one = 1
198208
def __bool__(self) -> Literal[False]:
199209
return False
200-
if E.x:
201-
"noop"
210+
211+
def print(s: str) -> None: ...
212+
213+
if E.zero:
214+
print("zero is true") # E: Statement is unreachable
215+
if not E.zero:
216+
print("zero is false")
217+
218+
if E.one:
219+
print("one is true") # E: Statement is unreachable
220+
if not E.one:
221+
print("one is false")
222+
[builtins fixtures/enum.pyi]
223+
224+
[case testEnumTruthynessStrEnum]
225+
# mypy: warn-unreachable
226+
import enum
227+
from typing_extensions import Literal
228+
class E(enum.StrEnum):
229+
empty = ""
230+
not_empty = "asdf"
231+
232+
def print(s: str) -> None: ...
233+
234+
if E.empty:
235+
print("empty is true")
236+
if not E.empty:
237+
print("empty is false")
238+
239+
if E.not_empty:
240+
print("not_empty is true")
241+
if not E.not_empty:
242+
print("not_empty is false")
202243
[builtins fixtures/enum.pyi]
203-
[out]
204-
main:9: error: Statement is unreachable
205244

206245
[case testEnumUnique]
207246
import enum

test-data/unit/fixtures/enum.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class tuple(Generic[T]):
1111
def __getitem__(self, x: int) -> T: pass
1212

1313
class int: pass
14-
class str: pass
14+
class str:
15+
def __len__(self) -> int: pass
16+
1517
class dict: pass
1618
class ellipsis: pass

0 commit comments

Comments
 (0)