|
3 | 3 | import typing
|
4 | 4 | from collections.abc import Awaitable
|
5 | 5 | from types import TracebackType
|
6 |
| -from typing import Any, Type |
| 6 | +from typing import Any, Type, overload |
7 | 7 |
|
8 | 8 | import _typeshed
|
9 | 9 | import typing_extensions
|
@@ -73,3 +73,97 @@ async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awa
|
73 | 73 | class BadSix:
|
74 | 74 | def __exit__(self, typ, exc, tb, weird_extra_arg, extra_arg2 = None) -> None: ... # PYI036: Extra arg must have default
|
75 | 75 | async def __aexit__(self, typ, exc, tb, *, weird_extra_arg) -> None: ... # PYI036: kwargs must have default
|
| 76 | + |
| 77 | +class AllPositionalOnlyArgs: |
| 78 | + def __exit__(self, typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None, /) -> None: ... |
| 79 | + async def __aexit__(self, typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None, /) -> None: ... |
| 80 | + |
| 81 | +class BadAllPositionalOnlyArgs: |
| 82 | + def __exit__(self, typ: type[Exception] | None, exc: BaseException | None, tb: TracebackType | None, /) -> None: ... |
| 83 | + async def __aexit__(self, typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType, /) -> None: ... |
| 84 | + |
| 85 | +# Definitions not in a class scope can do whatever, we don't care |
| 86 | +def __exit__(self, *args: bool) -> None: ... |
| 87 | +async def __aexit__(self, *, go_crazy: bytes) -> list[str]: ... |
| 88 | + |
| 89 | +# Here come the overloads... |
| 90 | + |
| 91 | +class AcceptableOverload1: |
| 92 | + @overload |
| 93 | + def __exit__(self, exc_typ: None, exc: None, exc_tb: None) -> None: ... |
| 94 | + @overload |
| 95 | + def __exit__(self, exc_typ: type[BaseException], exc: BaseException, exc_tb: TracebackType) -> None: ... |
| 96 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None) -> None: ... |
| 97 | + |
| 98 | +# Using `object` or `Unused` in an overload definition is kinda strange, |
| 99 | +# but let's allow it to be on the safe side |
| 100 | +class AcceptableOverload2: |
| 101 | + @overload |
| 102 | + def __exit__(self, exc_typ: None, exc: None, exc_tb: object) -> None: ... |
| 103 | + @overload |
| 104 | + def __exit__(self, exc_typ: Unused, exc: BaseException, exc_tb: object) -> None: ... |
| 105 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None) -> None: ... |
| 106 | + |
| 107 | +class AcceptableOverload3: |
| 108 | + # Just ignore any overloads that don't have exactly 3 annotated non-self parameters. |
| 109 | + # We don't have the ability (yet) to do arbitrary checking |
| 110 | + # of whether one function definition is a subtype of another... |
| 111 | + @overload |
| 112 | + def __exit__(self, exc_typ: bool, exc: bool, exc_tb: bool, weird_extra_arg: bool) -> None: ... |
| 113 | + @overload |
| 114 | + def __exit__(self, *args: object) -> None: ... |
| 115 | + def __exit__(self, *args: object) -> None: ... |
| 116 | + @overload |
| 117 | + async def __aexit__(self, exc_typ: bool, /, exc: bool, exc_tb: bool, *, keyword_only: str) -> None: ... |
| 118 | + @overload |
| 119 | + async def __aexit__(self, *args: object) -> None: ... |
| 120 | + async def __aexit__(self, *args: object) -> None: ... |
| 121 | + |
| 122 | +class AcceptableOverload4: |
| 123 | + # Same as above |
| 124 | + @overload |
| 125 | + def __exit__(self, exc_typ: type[Exception], exc: type[Exception], exc_tb: types.TracebackType) -> None: ... |
| 126 | + @overload |
| 127 | + def __exit__(self, *args: object) -> None: ... |
| 128 | + def __exit__(self, *args: object) -> None: ... |
| 129 | + @overload |
| 130 | + async def __aexit__(self, exc_typ: type[Exception], exc: type[Exception], exc_tb: types.TracebackType, *, extra: str = "foo") -> None: ... |
| 131 | + @overload |
| 132 | + async def __aexit__(self, exc_typ: None, exc: None, tb: None) -> None: ... |
| 133 | + async def __aexit__(self, *args: object) -> None: ... |
| 134 | + |
| 135 | +class StrangeNumberOfOverloads: |
| 136 | + # Only one overload? Type checkers will emit an error, but we should just ignore it |
| 137 | + @overload |
| 138 | + def __exit__(self, exc_typ: bool, exc: bool, tb: bool) -> None: ... |
| 139 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None) -> None: ... |
| 140 | + # More than two overloads? Anything could be going on; again, just ignore all the overloads |
| 141 | + @overload |
| 142 | + async def __aexit__(self, arg: bool) -> None: ... |
| 143 | + @overload |
| 144 | + async def __aexit__(self, arg: None, arg2: None, arg3: None) -> None: ... |
| 145 | + @overload |
| 146 | + async def __aexit__(self, arg: bool, arg2: bool, arg3: bool) -> None: ... |
| 147 | + async def __aexit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None) -> None: ... |
| 148 | + |
| 149 | +# TODO: maybe we should emit an error on this one as well? |
| 150 | +class BizarreAsyncSyncOverloadMismatch: |
| 151 | + @overload |
| 152 | + def __exit__(self, exc_typ: bool, exc: bool, tb: bool) -> None: ... |
| 153 | + @overload |
| 154 | + async def __exit__(self, exc_typ: bool, exc: bool, tb: bool) -> None: ... |
| 155 | + def __exit__(self, *args: object) -> None: ... |
| 156 | + |
| 157 | +class UnacceptableOverload1: |
| 158 | + @overload |
| 159 | + def __exit__(self, exc_typ: None, exc: None, tb: None) -> None: ... # Okay |
| 160 | + @overload |
| 161 | + def __exit__(self, exc_typ: Exception, exc: Exception, tb: TracebackType) -> None: ... # PYI036 |
| 162 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None) -> None: ... |
| 163 | + |
| 164 | +class UnacceptableOverload2: |
| 165 | + @overload |
| 166 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: None, tb: None) -> None: ... # PYI036 |
| 167 | + @overload |
| 168 | + def __exit__(self, exc_typ: object, exc: Exception, tb: builtins.TracebackType) -> None: ... # PYI036 |
| 169 | + def __exit__(self, exc_typ: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None) -> None: ... |
0 commit comments