51
51
TypedDictType ,
52
52
TypeOfAny ,
53
53
TypeStrVisitor ,
54
+ TypeVarLikeType ,
54
55
TypeVarTupleType ,
55
56
TypeVarType ,
56
57
UnionType ,
@@ -442,6 +443,13 @@ def check_specs_in_format_call(
442
443
def helpful_check (self , actual_type : ProperType , context : Context ) -> bool :
443
444
if isinstance (actual_type , (TupleType , TypedDictType , LiteralType )):
444
445
return True
446
+ if isinstance (actual_type , TypeVarType ):
447
+ if actual_type .values :
448
+ for value in actual_type .values :
449
+ self .helpful_check (get_proper_type (value ), context )
450
+ return False
451
+ while isinstance (actual_type , TypeVarLikeType ):
452
+ actual_type = actual_type .upper_bound
445
453
bad_builtin = False
446
454
if isinstance (actual_type , Instance ):
447
455
if "dataclass" in actual_type .type .metadata :
@@ -464,13 +472,11 @@ def helpful_check(self, actual_type: ProperType, context: Context) -> bool:
464
472
if base .module_name == "builtins" :
465
473
return True
466
474
type_string = actual_type .accept (TypeStrVisitor (options = self .chk .options ))
467
- if (
468
- custom_special_method (actual_type , "__format__" )
469
- or custom_special_method (actual_type , "__str__" )
470
- or custom_special_method (actual_type , "__repr__" )
471
- ):
475
+ if custom_special_method (actual_type , ("__format__" , "__str__" , "__repr__" )):
472
476
return True
473
- if bad_builtin or isinstance (actual_type , NoneType ):
477
+ if bad_builtin or (
478
+ not self .msg .options .helpful_string_allow_none and isinstance (actual_type , NoneType )
479
+ ):
474
480
self .msg .fail (
475
481
f'The string for "{ type_string } " isn\' t helpful in a user-facing or semantic string' ,
476
482
context ,
0 commit comments