@@ -4,7 +4,7 @@ from _typeshed import FileDescriptorOrPath, Unused
4
4
from abc import abstractmethod
5
5
from collections .abc import AsyncGenerator , AsyncIterator , Awaitable , Callable , Generator , Iterator
6
6
from types import TracebackType
7
- from typing import IO , Any , Generic , Protocol , TypeVar , overload , runtime_checkable
7
+ from typing import IO , Any , Generic , Literal , Protocol , TypeVar , overload , runtime_checkable
8
8
from typing_extensions import ParamSpec , Self , TypeAlias
9
9
10
10
__all__ = [
@@ -67,8 +67,23 @@ class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator):
67
67
if sys .version_info >= (3 , 9 ):
68
68
def __exit__ (
69
69
self , typ : type [BaseException ] | None , value : BaseException | None , traceback : TracebackType | None
70
- ) -> bool | None : ...
70
+ ) -> Literal [False ]: ...
71
+ elif sys .version_info >= (3 , 7 ):
72
+ def __exit__ (
73
+ self , type : type [BaseException ] | None , value : BaseException | None , traceback : TracebackType | None
74
+ ) -> Literal [False ]: ...
71
75
else :
76
+ # python 3.7 fixes an issue where generators could incorrectly suppress StopIteration exceptions
77
+ # (see https://peps.python.org/pep-0479/). while it's still technically possible to craft a generator that
78
+ # does, it's an extreme edge case that you need to go out of your way to cause. so we change the return type
79
+ # to `Literal[False]` to prevent it from assuming every context manager can suppress exceptions. the only
80
+ # reason this isn't an issue in upstream pyright/mypy is because they both "fix" this problem in the
81
+ # stupidest way imaginable, by special-casing `bool | None` to mean `Literal[False]` instead.
82
+
83
+ # the tradeoff with my fix is that python <=3.7 users will experience plenty of annoying errors caused by
84
+ # basedpyright being overly strict and assuming variables set inside context managers can be unbound in case
85
+ # the exception gets suppressed. i could do some special casing to address this, but python 3.6 is deprecated
86
+ # anyway and you should just update to a supported version of python instead.
72
87
def __exit__ (
73
88
self , type : type [BaseException ] | None , value : BaseException | None , traceback : TracebackType | None
74
89
) -> bool | None : ...
0 commit comments