40
40
from mypy .parse import parse
41
41
42
42
FormatStringExpr = Union [StrExpr , BytesExpr , UnicodeExpr ]
43
- Checkers = Tuple [Callable [[Expression ], None ], Callable [[Type ], None ]]
43
+ Checkers = Tuple [Callable [[Expression ], None ], Callable [[Type ], bool ]]
44
44
MatchMap = Dict [Tuple [int , int ], Match [str ]] # span -> match
45
45
46
46
@@ -98,23 +98,8 @@ def compile_new_format_re(custom_spec: bool) -> Pattern[str]:
98
98
DUMMY_FIELD_NAME : Final = "__dummy_name__"
99
99
100
100
# Format types supported by str.format() for builtin classes.
101
- SUPPORTED_TYPES_NEW : Final = {
102
- "b" ,
103
- "c" ,
104
- "d" ,
105
- "e" ,
106
- "E" ,
107
- "f" ,
108
- "F" ,
109
- "g" ,
110
- "G" ,
111
- "n" ,
112
- "o" ,
113
- "s" ,
114
- "x" ,
115
- "X" ,
116
- "%" ,
117
- }
101
+ SUPPORTED_TYPES_NEW : Final = {"b" , "c" , "d" , "e" , "E" , "f" , "F" ,
102
+ "g" , "G" , "n" , "o" , "s" , "x" , "X" , "%" }
118
103
119
104
# Types that require either int or float.
120
105
NUMERIC_TYPES_OLD : Final = {"d" , "i" , "o" , "u" , "x" , "X" , "e" , "E" , "f" , "F" , "g" , "G" }
@@ -813,22 +798,22 @@ def checkers_for_star(self, context: Context) -> Checkers:
813
798
"""
814
799
expected = self .named_type ('builtins.int' )
815
800
816
- def check_type (type : Type ) -> None :
801
+ def check_type (type : Type ) -> bool :
817
802
expected = self .named_type ('builtins.int' )
818
- self .chk .check_subtype (type , expected , context , '* wants int' ,
819
- code = codes .STRING_FORMATTING )
803
+ return self .chk .check_subtype (type , expected , context , '* wants int' ,
804
+ code = codes .STRING_FORMATTING )
820
805
821
806
def check_expr (expr : Expression ) -> None :
822
807
type = self .accept (expr , expected )
823
808
check_type (type )
824
809
825
810
return check_expr , check_type
826
811
827
- def check_placeholder_type (self , typ : Type , expected_type : Type , context : Context ) -> None :
828
- self .chk .check_subtype (typ , expected_type , context ,
829
- message_registry .INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION ,
830
- 'expression has type' , 'placeholder has type' ,
831
- code = codes .STRING_FORMATTING )
812
+ def check_placeholder_type (self , typ : Type , expected_type : Type , context : Context ) -> bool :
813
+ return self .chk .check_subtype (typ , expected_type , context ,
814
+ message_registry .INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION ,
815
+ 'expression has type' , 'placeholder has type' ,
816
+ code = codes .STRING_FORMATTING )
832
817
833
818
def checkers_for_regular_type (self , type : str ,
834
819
context : Context ,
@@ -840,19 +825,20 @@ def checkers_for_regular_type(self, type: str,
840
825
if expected_type is None :
841
826
return None
842
827
843
- def check_type (typ : Type ) -> None :
828
+ def check_type (typ : Type ) -> bool :
844
829
assert expected_type is not None
845
- self .check_placeholder_type (typ , expected_type , context )
846
- if type == 's' :
847
- self .check_s_special_cases (expr , typ , context )
830
+ ret = self .check_placeholder_type (typ , expected_type , context )
831
+ if ret and type == 's' :
832
+ ret = self .check_s_special_cases (expr , typ , context )
833
+ return ret
848
834
849
835
def check_expr (expr : Expression ) -> None :
850
836
type = self .accept (expr , expected_type )
851
837
check_type (type )
852
838
853
839
return check_expr , check_type
854
840
855
- def check_s_special_cases (self , expr : FormatStringExpr , typ : Type , context : Context ) -> None :
841
+ def check_s_special_cases (self , expr : FormatStringExpr , typ : Type , context : Context ) -> bool :
856
842
"""Additional special cases for %s in bytes vs string context."""
857
843
if isinstance (expr , StrExpr ):
858
844
# Couple special cases for string formatting.
@@ -862,6 +848,7 @@ def check_s_special_cases(self, expr: FormatStringExpr, typ: Type, context: Cont
862
848
"On Python 3 '%s' % b'abc' produces \" b'abc'\" , not 'abc'; "
863
849
"use '%r' % b'abc' if this is desired behavior" ,
864
850
context , code = codes .STR_BYTES_PY3 )
851
+ return False
865
852
if self .chk .options .python_version < (3 , 0 ):
866
853
if has_type_component (typ , 'builtins.unicode' ):
867
854
self .unicode_upcast = True
@@ -871,6 +858,8 @@ def check_s_special_cases(self, expr: FormatStringExpr, typ: Type, context: Cont
871
858
if has_type_component (typ , 'builtins.str' ):
872
859
self .msg .fail ("On Python 3 b'%s' requires bytes, not string" , context ,
873
860
code = codes .STRING_FORMATTING )
861
+ return False
862
+ return True
874
863
875
864
def checkers_for_c_type (self , type : str ,
876
865
context : Context ,
@@ -882,20 +871,30 @@ def checkers_for_c_type(self, type: str,
882
871
if expected_type is None :
883
872
return None
884
873
885
- def check_type (type : Type ) -> None :
874
+ def check_type (type : Type ) -> bool :
886
875
assert expected_type is not None
887
- self .check_placeholder_type (type , expected_type , context )
876
+ if self .chk .options .python_version >= (3 , 0 ) and isinstance (format_expr , BytesExpr ):
877
+ err_msg = '"%c" requires an integer in range(256) or a single byte'
878
+ else :
879
+ err_msg = '"%c" requires int or char'
880
+ return self .chk .check_subtype (type , expected_type , context , err_msg ,
881
+ 'expression has type' ,
882
+ code = codes .STRING_FORMATTING )
888
883
889
884
def check_expr (expr : Expression ) -> None :
890
885
"""int, or str with length 1"""
891
886
type = self .accept (expr , expected_type )
892
- # TODO: Use the same the error message when incompatible types match %c
893
- # Python 3 doesn't support b'%c' % str
894
- if not (self .chk .options .python_version >= (3 , 0 )
895
- and isinstance (format_expr , BytesExpr )):
896
- if isinstance (expr , (StrExpr , BytesExpr )) and len (expr .value ) != 1 :
887
+ # We need further check with expr to make sure that
888
+ # it has exact one char or one single byte.
889
+ if check_type (type ):
890
+ # Python 3 doesn't support b'%c' % str
891
+ if (self .chk .options .python_version >= (3 , 0 )
892
+ and isinstance (format_expr , BytesExpr )
893
+ and isinstance (expr , BytesExpr ) and len (expr .value ) != 1 ):
894
+ self .msg .requires_int_or_single_byte (context )
895
+ # In Python 2, b'%c' is the same as '%c'
896
+ elif isinstance (expr , (StrExpr , BytesExpr )) and len (expr .value ) != 1 :
897
897
self .msg .requires_int_or_char (context )
898
- check_type (type )
899
898
900
899
return check_expr , check_type
901
900
0 commit comments