@@ -661,7 +661,8 @@ def test_g_format_has_no_trailing_zeros(self):
661661 self .assertEqual (format (12300050.0 , "#.6g" ), "1.23000e+07" )
662662
663663 def test_with_two_commas_in_format_specifier (self ):
664- error_msg = re .escape ("Cannot specify grouping ',' more than once" )
664+ error_msg = re .escape (
665+ "Cannot specify grouping character ',' more than once" )
665666 with self .assertRaisesRegex (ValueError , error_msg ):
666667 '{:,,}' .format (1 )
667668 with self .assertRaisesRegex (ValueError , error_msg ):
@@ -670,7 +671,8 @@ def test_with_two_commas_in_format_specifier(self):
670671 '{:.,,f}' .format (1.1 )
671672
672673 def test_with_two_underscore_in_format_specifier (self ):
673- error_msg = re .escape ("Cannot specify grouping '_' more than once" )
674+ error_msg = re .escape (
675+ "Cannot specify grouping character '_' more than once" )
674676 with self .assertRaisesRegex (ValueError , error_msg ):
675677 '{:__}' .format (1 )
676678 with self .assertRaisesRegex (ValueError , error_msg ):
@@ -696,32 +698,153 @@ def test_with_an_underscore_and_a_comma_in_format_specifier(self):
696698 with self .assertRaisesRegex (ValueError , error_msg ):
697699 '{:._,f}' .format (1.1 )
698700
699- def test_better_error_message_format (self ):
701+ def test_invalid_format_specifier_error_message (self ):
700702 # https://bugs.python.org/issue20524
701703 for value in [12j , 12 , 12.0 , "12" ]:
702- with self . subTest ( value = value ) :
704+ for bad_spec in [ "%M" , "ЫйXЯЧ" , " \n ' \\ " ] :
703705 # The format spec must be invalid for all types we're testing.
704- # '%M' will suffice.
705- bad_format_spec = '%M'
706- err = re .escape ("Invalid format specifier "
707- f"'{ bad_format_spec } ' for object of type "
708- f"'{ type (value ).__name__ } '" )
709- with self .assertRaisesRegex (ValueError , err ):
710- f"xx{{value:{ bad_format_spec } }}yy" .format (value = value )
711-
712- # Also test the builtin format() function.
713- with self .assertRaisesRegex (ValueError , err ):
714- format (value , bad_format_spec )
715-
716- # Also test f-strings.
717- with self .assertRaisesRegex (ValueError , err ):
718- eval ("f'xx{value:{bad_format_spec}}yy'" )
719-
720- def test_unicode_in_error_message (self ):
721- str_err = re .escape (
722- "Invalid format specifier '%ЫйЯЧ' for object of type 'str'" )
723- with self .assertRaisesRegex (ValueError , str_err ):
724- "{a:%ЫйЯЧ}" .format (a = 'a' )
706+ with self .subTest (value = value , bad_spec = bad_spec ):
707+ err = re .escape ("Invalid format specifier "
708+ f"{ bad_spec !r} for object of type "
709+ f"'{ type (value ).__name__ } '" )
710+ with self .assertRaisesRegex (ValueError , err ):
711+ f"xx{{value:{ bad_spec } }}yy" .format (value = value )
712+
713+ # Also test the builtin format() function.
714+ with self .assertRaisesRegex (ValueError , err ):
715+ format (value , bad_spec )
716+
717+ # Also test f-strings.
718+ with self .assertRaisesRegex (ValueError , err ):
719+ eval ("f'xx{value:{bad_spec}}yy'" )
720+
721+ def test_invalid_specifier_type_error_message (self ):
722+ for value in [12j , 12 , 12.0 , "12" ]:
723+ for bad_spec , repr in [
724+ ("M" , "'M'" ),
725+ ("10$" , "'$'" ),
726+ ("\t " , "U+0009" ),
727+ (",\x7f " , "U+007F" ),
728+ ("о" , "'о' (U+043E)" ),
729+ ("+#020,🐍" , "'🐍' (U+1F40D)" )
730+ ]:
731+ with self .subTest (value = value , bad_spec = bad_spec ):
732+ err = re .escape ("Unknown format code "
733+ f"{ repr } for object of type "
734+ f"'{ type (value ).__name__ } '" )
735+ with self .assertRaisesRegex (ValueError , err ):
736+ f"xx{{value:{ bad_spec } }}yy" .format (value = value )
737+
738+ # Also test the builtin format() function.
739+ with self .assertRaisesRegex (ValueError , err ):
740+ format (value , bad_spec )
741+
742+ # Also test f-strings.
743+ with self .assertRaisesRegex (ValueError , err ):
744+ eval ("f'xx{value:{bad_spec}}yy'" )
745+
746+ def test_specifier_grouping_with_types (self ):
747+ def assertEqualGroup (spec , value , expected ):
748+ with self .subTest (spec = spec , value = value ):
749+ self .assertEqual (("{:%s}" % spec ).format (value ), expected )
750+ self .assertEqual (format (value , spec ), expected )
751+ self .assertEqual (f"{ value :{spec }} " , expected )
752+
753+ def assertRaisesGroup (spec , value , error_msg ):
754+ with self .subTest (spec = spec , value = value ):
755+ error_msg = re .escape (error_msg )
756+ with self .assertRaisesRegex (ValueError , error_msg ):
757+ ("{:%s}" % spec ).format (value )
758+ with self .assertRaisesRegex (ValueError , error_msg ):
759+ format (value , spec )
760+ with self .assertRaisesRegex (ValueError , error_msg ):
761+ f"{ value :{spec }} "
762+
763+ value = 1234567
764+ assertEqualGroup ("," , value , "1,234,567" )
765+ assertRaisesGroup ("._" , value ,
766+ "Cannot specify '_' in fractional part with 'd'" )
767+ assertEqualGroup (",d" , value , "1,234,567" )
768+ assertRaisesGroup ("._d" , value ,
769+ "Cannot specify '_' in fractional part with 'd'" )
770+ assertEqualGroup (",e" , value , "1.234567e+06" )
771+ assertEqualGroup ("._e" , value , "1.234_567e+06" )
772+ assertRaisesGroup (",b" , value , "Cannot specify ',' with 'b'" )
773+ assertEqualGroup ("_b" , 1234 , "100_1101_0010" )
774+ assertRaisesGroup ("._b" , value ,
775+ "Cannot specify '_' in fractional part with 'b'" )
776+ assertRaisesGroup (",s" , value , "Cannot specify ',' with 's'" )
777+ assertRaisesGroup ("._s" , value ,
778+ "Cannot specify '_' in fractional part with 's'" )
779+ assertRaisesGroup (",n" , value , "Cannot specify ',' with 'n'" )
780+ assertRaisesGroup ("._n" , value ,
781+ "Cannot specify '_' in fractional part with 'n'" )
782+
783+ value = 1234567.1234567
784+ assertEqualGroup ("," , value , "1,234,567.1234567" )
785+ assertEqualGroup ("._" , value , "1234567.123_456_7" )
786+ assertRaisesGroup (",d" , value ,
787+ "Unknown format code 'd' for object of type 'float'" )
788+ assertRaisesGroup ("._d" , value ,
789+ "Cannot specify '_' in fractional part with 'd'" )
790+ assertEqualGroup (",e" , value , "1.234567e+06" )
791+ assertEqualGroup ("._e" , value , "1.234_567e+06" )
792+ assertRaisesGroup (",b" , value , "Cannot specify ',' with 'b'" )
793+ assertRaisesGroup ("_b" , value ,
794+ "Unknown format code 'b' for object of type 'float'" )
795+ assertRaisesGroup ("._b" , value ,
796+ "Cannot specify '_' in fractional part with 'b'" )
797+ assertRaisesGroup (",s" , value , "Cannot specify ',' with 's'" )
798+ assertRaisesGroup ("._s" , value ,
799+ "Cannot specify '_' in fractional part with 's'" )
800+ assertRaisesGroup (",n" , value , "Cannot specify ',' with 'n'" )
801+ assertRaisesGroup ("._n" , value ,
802+ "Cannot specify '_' in fractional part with 'n'" )
803+
804+ value = 1234567.1234567 + 1234567.1234567j
805+ assertEqualGroup ("," , value , "(1,234,567.1234567+1,234,567.1234567j)" )
806+ assertEqualGroup ("._" , value , "(1234567.123_456_7+1234567.123_456_7j)" )
807+ assertRaisesGroup (",d" , value ,
808+ "Unknown format code 'd' for object of type 'complex'" )
809+ assertRaisesGroup ("._d" , value ,
810+ "Cannot specify '_' in fractional part with 'd'" )
811+ assertEqualGroup (",e" , value , "1.234567e+06+1.234567e+06j" )
812+ assertEqualGroup ("._e" , value , "1.234_567e+06+1.234_567e+06j" )
813+ assertRaisesGroup (",b" , value , "Cannot specify ',' with 'b'" )
814+ assertRaisesGroup ("_b" , value ,
815+ "Unknown format code 'b' for object of type 'complex'" )
816+ assertRaisesGroup ("._b" , value ,
817+ "Cannot specify '_' in fractional part with 'b'" )
818+ assertRaisesGroup (",s" , value , "Cannot specify ',' with 's'" )
819+ assertRaisesGroup ("._s" , value ,
820+ "Cannot specify '_' in fractional part with 's'" )
821+ assertRaisesGroup (",n" , value , "Cannot specify ',' with 'n'" )
822+ assertRaisesGroup ("._n" , value ,
823+ "Cannot specify '_' in fractional part with 'n'" )
824+
825+ value = "1234567"
826+ assertRaisesGroup ("," , value , "Cannot specify ',' with 's'" )
827+ assertRaisesGroup ("._" , value ,
828+ "Cannot specify '_' in fractional part with 's'" )
829+ assertRaisesGroup (",d" , value ,
830+ "Unknown format code 'd' for object of type 'str'" )
831+ assertRaisesGroup ("._d" , value ,
832+ "Cannot specify '_' in fractional part with 'd'" )
833+ assertRaisesGroup (",e" , value ,
834+ "Unknown format code 'e' for object of type 'str'" )
835+ assertRaisesGroup ("._e" , value ,
836+ "Unknown format code 'e' for object of type 'str'" )
837+ assertRaisesGroup (",b" , value , "Cannot specify ',' with 'b'" )
838+ assertRaisesGroup ("_b" , value ,
839+ "Unknown format code 'b' for object of type 'str'" )
840+ assertRaisesGroup ("._b" , value ,
841+ "Cannot specify '_' in fractional part with 'b'" )
842+ assertRaisesGroup (",s" , value , "Cannot specify ',' with 's'" )
843+ assertRaisesGroup ("._s" , value ,
844+ "Cannot specify '_' in fractional part with 's'" )
845+ assertRaisesGroup (",n" , value , "Cannot specify ',' with 'n'" )
846+ assertRaisesGroup ("._n" , value ,
847+ "Cannot specify '_' in fractional part with 'n'" )
725848
726849 def test_negative_zero (self ):
727850 ## default behavior
0 commit comments