File tree Expand file tree Collapse file tree 3 files changed +75
-2
lines changed Expand file tree Collapse file tree 3 files changed +75
-2
lines changed Original file line number Diff line number Diff line change @@ -4220,9 +4220,19 @@ def is_typed_callable(c: Optional[Type]) -> bool:
4220
4220
4221
4221
4222
4222
def is_untyped_decorator (typ : Optional [Type ]) -> bool :
4223
- if not typ or not isinstance ( typ , CallableType ) :
4223
+ if not typ :
4224
4224
return True
4225
- return typ .implicit
4225
+ elif isinstance (typ , CallableType ):
4226
+ return not is_typed_callable (typ )
4227
+ elif isinstance (typ , Instance ):
4228
+ method = typ .type .get_method ('__call__' )
4229
+ if method :
4230
+ return not is_typed_callable (method .type )
4231
+ else :
4232
+ return False
4233
+ elif isinstance (typ , Overloaded ):
4234
+ return any (is_untyped_decorator (item ) for item in typ .items ())
4235
+ return True
4226
4236
4227
4237
4228
4238
def is_static (func : Union [FuncBase , Decorator ]) -> bool :
Original file line number Diff line number Diff line change @@ -132,6 +132,45 @@ def d3(p) -> Any:
132
132
@d1 # E: Untyped decorator makes function "f" untyped
133
133
def f() -> None: pass
134
134
135
+ [case testDisallowUntypedDecoratorsCallableInstance]
136
+ # flags: --disallow-untyped-decorators
137
+ from typing import Callable
138
+
139
+ class TypedDecorator:
140
+ def __call__(self, c: Callable) -> Callable:
141
+ return function
142
+
143
+ class UntypedDecorator:
144
+ def __call__(self, c):
145
+ return function
146
+
147
+ @TypedDecorator()
148
+ def f() -> None: pass
149
+
150
+ @UntypedDecorator() # E: Untyped decorator makes function "g" untyped
151
+ def g() -> None: pass
152
+
153
+ @TypedDecorator()
154
+ @UntypedDecorator() # E: Untyped decorator makes function "h" untyped
155
+ def h() -> None: pass
156
+
157
+ @UntypedDecorator() # E: Untyped decorator makes function "i" untyped
158
+ @TypedDecorator()
159
+ def i() -> None: pass
160
+
161
+ reveal_type(f) # E: Revealed type is 'def (*Any, **Any) -> Any'
162
+ reveal_type(g) # E: Revealed type is 'Any'
163
+ reveal_type(h) # E: Revealed type is 'def (*Any, **Any) -> Any'
164
+ reveal_type(i) # E: Revealed type is 'Any'
165
+
166
+ [case testDisallowUntypedDecoratorsNonCallableInstance]
167
+ # flags: --disallow-untyped-decorators
168
+ class Decorator:
169
+ pass
170
+
171
+ @Decorator() # E: "Decorator" not callable
172
+ def f() -> None: pass
173
+
135
174
[case testSubclassingAny]
136
175
# flags: --disallow-subclassing-any
137
176
from typing import Any
Original file line number Diff line number Diff line change @@ -4849,3 +4849,27 @@ reveal_type(b) # E: Revealed type is 'builtins.int'
4849
4849
c = single_plausible([Other()]) # E: List item 0 has incompatible type "Other"; expected "str"
4850
4850
reveal_type(c) # E: Revealed type is 'builtins.str'
4851
4851
[builtins fixtures/list.pyi]
4852
+
4853
+ [case testDisallowUntypedDecoratorsOverload]
4854
+ # flags: --disallow-untyped-decorators
4855
+ from typing import Any, Callable, overload, TypeVar
4856
+
4857
+ F = TypeVar('F', bound=Callable[..., Any])
4858
+
4859
+ @overload
4860
+ def dec(x: F) -> F: ...
4861
+ @overload
4862
+ def dec(x: str) -> Callable[[F], F]: ...
4863
+ def dec(x) -> Any:
4864
+ pass
4865
+
4866
+ @dec
4867
+ def f(name: str) -> int:
4868
+ return 0
4869
+
4870
+ @dec('abc')
4871
+ def g(name: str) -> int:
4872
+ return 0
4873
+
4874
+ reveal_type(f) # E: Revealed type is 'def (name: builtins.str) -> builtins.int'
4875
+ reveal_type(g) # E: Revealed type is 'def (name: builtins.str) -> builtins.int'
You can’t perform that action at this time.
0 commit comments