55
55
'mypy_extensions.KwArg' : ARG_STAR2 ,
56
56
} # type: Final
57
57
58
+ GENERIC_STUB_NOT_AT_RUNTIME_TYPES = {
59
+ 'queue.Queue' ,
60
+ 'builtins._PathLike' ,
61
+ } # type: Final
62
+
58
63
59
64
def analyze_type_alias (node : Expression ,
60
65
api : SemanticAnalyzerCoreInterface ,
@@ -221,8 +226,13 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
221
226
res = get_proper_type (res )
222
227
if (isinstance (res , Instance ) and len (res .args ) != len (res .type .type_vars ) and
223
228
not self .defining_alias ):
224
- fix_instance (res , self .fail , disallow_any = disallow_any , use_generic_error = True ,
225
- unexpanded_type = t )
229
+ fix_instance (
230
+ res ,
231
+ self .fail ,
232
+ self .note ,
233
+ disallow_any = disallow_any ,
234
+ use_generic_error = True ,
235
+ unexpanded_type = t )
226
236
return res
227
237
elif isinstance (node , TypeInfo ):
228
238
return self .analyze_type_with_type_info (node , t .args , t )
@@ -319,13 +329,14 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt
319
329
320
330
def get_omitted_any (self , typ : Type , fullname : Optional [str ] = None ) -> AnyType :
321
331
disallow_any = not self .is_typeshed_stub and self .options .disallow_any_generics
322
- return get_omitted_any (disallow_any , self .fail , typ , fullname )
332
+ return get_omitted_any (disallow_any , self .fail , self . note , typ , fullname )
323
333
324
334
def analyze_type_with_type_info (self , info : TypeInfo , args : List [Type ], ctx : Context ) -> Type :
325
335
"""Bind unbound type when were able to find target TypeInfo.
326
336
327
337
This handles simple cases like 'int', 'modname.UserClass[str]', etc.
328
338
"""
339
+
329
340
if len (args ) > 0 and info .fullname () == 'builtins.tuple' :
330
341
fallback = Instance (info , [AnyType (TypeOfAny .special_form )], ctx .line )
331
342
return TupleType (self .anal_array (args ), fallback , ctx .line )
@@ -337,7 +348,7 @@ def analyze_type_with_type_info(self, info: TypeInfo, args: List[Type], ctx: Con
337
348
instance = Instance (info , self .anal_array (args ), ctx .line , ctx .column )
338
349
# Check type argument count.
339
350
if len (instance .args ) != len (info .type_vars ) and not self .defining_alias :
340
- fix_instance (instance , self .fail ,
351
+ fix_instance (instance , self .fail , self . note ,
341
352
disallow_any = self .options .disallow_any_generics and
342
353
not self .is_typeshed_stub )
343
354
@@ -891,10 +902,10 @@ def tuple_type(self, items: List[Type]) -> TupleType:
891
902
TypeVarList = List [Tuple [str , TypeVarExpr ]]
892
903
893
904
# Mypyc doesn't support callback protocols yet.
894
- FailCallback = Callable [[str , Context , DefaultNamedArg (Optional [ErrorCode ], 'code' )], None ]
905
+ MsgCallback = Callable [[str , Context , DefaultNamedArg (Optional [ErrorCode ], 'code' )], None ]
895
906
896
907
897
- def get_omitted_any (disallow_any : bool , fail : FailCallback ,
908
+ def get_omitted_any (disallow_any : bool , fail : MsgCallback , note : MsgCallback ,
898
909
typ : Type , fullname : Optional [str ] = None ,
899
910
unexpanded_type : Optional [Type ] = None ) -> AnyType :
900
911
if disallow_any :
@@ -907,17 +918,31 @@ def get_omitted_any(disallow_any: bool, fail: FailCallback,
907
918
typ = unexpanded_type or typ
908
919
type_str = typ .name if isinstance (typ , UnboundType ) else format_type_bare (typ )
909
920
910
- fail (message_registry .BARE_GENERIC .format (quote_type_string (type_str )), typ ,
911
- code = codes .TYPE_ARG )
921
+ fail (
922
+ message_registry .BARE_GENERIC .format (
923
+ quote_type_string (type_str )),
924
+ typ ,
925
+ code = codes .TYPE_ARG )
926
+
927
+ if fullname in GENERIC_STUB_NOT_AT_RUNTIME_TYPES :
928
+ # Recommend `from __future__ import annotations` or to put type in quotes
929
+ # (string literal escaping) for classes not generic at runtime
930
+ note (
931
+ "Subscripting classes that are not generic at runtime may require "
932
+ "escaping, see https://mypy.readthedocs.io/"
933
+ "en/latest/common_issues.html#not-generic-runtime" ,
934
+ typ ,
935
+ code = codes .TYPE_ARG )
936
+
912
937
any_type = AnyType (TypeOfAny .from_error , line = typ .line , column = typ .column )
913
938
else :
914
939
any_type = AnyType (TypeOfAny .from_omitted_generics , line = typ .line , column = typ .column )
915
940
return any_type
916
941
917
942
918
- def fix_instance (t : Instance , fail : FailCallback ,
943
+ def fix_instance (t : Instance , fail : MsgCallback , note : MsgCallback ,
919
944
disallow_any : bool , use_generic_error : bool = False ,
920
- unexpanded_type : Optional [Type ] = None ) -> None :
945
+ unexpanded_type : Optional [Type ] = None , ) -> None :
921
946
"""Fix a malformed instance by replacing all type arguments with Any.
922
947
923
948
Also emit a suitable error if this is not due to implicit Any's.
@@ -927,7 +952,7 @@ def fix_instance(t: Instance, fail: FailCallback,
927
952
fullname = None # type: Optional[str]
928
953
else :
929
954
fullname = t .type .fullname ()
930
- any_type = get_omitted_any (disallow_any , fail , t , fullname , unexpanded_type )
955
+ any_type = get_omitted_any (disallow_any , fail , note , t , fullname , unexpanded_type )
931
956
t .args = [any_type ] * len (t .type .type_vars )
932
957
return
933
958
# Invalid number of type parameters.
@@ -950,7 +975,7 @@ def fix_instance(t: Instance, fail: FailCallback,
950
975
951
976
952
977
def expand_type_alias (target : Type , alias_tvars : List [str ], args : List [Type ],
953
- fail : FailCallback , no_args : bool , ctx : Context , * ,
978
+ fail : MsgCallback , no_args : bool , ctx : Context , * ,
954
979
unexpanded_type : Optional [Type ] = None ,
955
980
disallow_any : bool = False ) -> Type :
956
981
"""Expand a (generic) type alias target following the rules outlined in TypeAlias docstring.
@@ -998,7 +1023,7 @@ def set_any_tvars(tp: Type, vars: List[str],
998
1023
newline : int , newcolumn : int , * ,
999
1024
from_error : bool = False ,
1000
1025
disallow_any : bool = False ,
1001
- fail : Optional [FailCallback ] = None ,
1026
+ fail : Optional [MsgCallback ] = None ,
1002
1027
unexpanded_type : Optional [Type ] = None ) -> ProperType :
1003
1028
if from_error or disallow_any :
1004
1029
type_of_any = TypeOfAny .from_error
@@ -1181,20 +1206,21 @@ def make_optional_type(t: Type) -> Type:
1181
1206
return UnionType ([t , NoneType ()], t .line , t .column )
1182
1207
1183
1208
1184
- def fix_instance_types (t : Type , fail : FailCallback ) -> None :
1209
+ def fix_instance_types (t : Type , fail : MsgCallback , note : MsgCallback ) -> None :
1185
1210
"""Recursively fix all instance types (type argument count) in a given type.
1186
1211
1187
1212
For example 'Union[Dict, List[str, int]]' will be transformed into
1188
1213
'Union[Dict[Any, Any], List[Any]]' in place.
1189
1214
"""
1190
- t .accept (InstanceFixer (fail ))
1215
+ t .accept (InstanceFixer (fail , note ))
1191
1216
1192
1217
1193
1218
class InstanceFixer (TypeTraverserVisitor ):
1194
- def __init__ (self , fail : FailCallback ) -> None :
1219
+ def __init__ (self , fail : MsgCallback , note : MsgCallback ) -> None :
1195
1220
self .fail = fail
1221
+ self .note = note
1196
1222
1197
1223
def visit_instance (self , typ : Instance ) -> None :
1198
1224
super ().visit_instance (typ )
1199
1225
if len (typ .args ) != len (typ .type .type_vars ):
1200
- fix_instance (typ , self .fail , disallow_any = False , use_generic_error = True )
1226
+ fix_instance (typ , self .fail , self . note , disallow_any = False , use_generic_error = True )
0 commit comments