@@ -652,11 +652,16 @@ impl CFormatBytes {
652
652
let ( num_specifiers, mapping_required) = check_specifiers ( self . parts . as_slice ( ) , vm) ?;
653
653
let mut result = vec ! [ ] ;
654
654
655
+ let is_mapping = values_obj. class ( ) . has_attr ( "__getitem__" )
656
+ && !values_obj. isinstance ( & vm. ctx . types . tuple_type )
657
+ && !values_obj. isinstance ( & vm. ctx . types . str_type ) ;
658
+
655
659
if num_specifiers == 0 {
656
660
// literal only
657
- return if values_obj. isinstance ( & vm. ctx . types . dict_type )
658
- || ( values_obj. isinstance ( & vm. ctx . types . tuple_type )
659
- && tuple:: get_value ( & values_obj) . is_empty ( ) )
661
+ return if is_mapping
662
+ || values_obj
663
+ . payload :: < tuple:: PyTuple > ( )
664
+ . map_or ( false , |e| e. borrow_value ( ) . is_empty ( ) )
660
665
{
661
666
for ( _, part) in & mut self . parts {
662
667
match part {
@@ -674,7 +679,7 @@ impl CFormatBytes {
674
679
675
680
if mapping_required {
676
681
// dict
677
- return if values_obj . isinstance ( & vm . ctx . types . dict_type ) {
682
+ return if is_mapping {
678
683
for ( _, part) in & mut self . parts {
679
684
match part {
680
685
CFormatPart :: Literal ( literal) => result. append ( literal) ,
@@ -695,15 +700,12 @@ impl CFormatBytes {
695
700
}
696
701
697
702
// tuple
698
- let values;
699
- let vec;
700
- let mut value_iter = if values_obj. isinstance ( & vm. ctx . types . tuple_type ) {
701
- values = tuple:: get_value ( & values_obj) ;
702
- values. iter ( )
703
+ let values = if let Some ( tup) = values_obj. payload_if_subclass :: < tuple:: PyTuple > ( vm) {
704
+ tup. borrow_value ( )
703
705
} else {
704
- vec = vec ! [ values_obj] ;
705
- vec. iter ( )
706
+ std:: slice:: from_ref ( & values_obj)
706
707
} ;
708
+ let mut value_iter = values. iter ( ) ;
707
709
708
710
for ( _, part) in & mut self . parts {
709
711
match part {
@@ -725,7 +727,7 @@ impl CFormatBytes {
725
727
}
726
728
727
729
// check that all arguments were converted
728
- if value_iter. next ( ) . is_some ( ) {
730
+ if value_iter. next ( ) . is_some ( ) && !is_mapping {
729
731
Err ( vm
730
732
. new_type_error ( "not all arguments converted during string formatting" . to_owned ( ) ) )
731
733
} else {
@@ -802,11 +804,16 @@ impl CFormatString {
802
804
let ( num_specifiers, mapping_required) = check_specifiers ( self . parts . as_slice ( ) , vm) ?;
803
805
let mut result = String :: new ( ) ;
804
806
807
+ let is_mapping = values_obj. class ( ) . has_attr ( "__getitem__" )
808
+ && !values_obj. isinstance ( & vm. ctx . types . tuple_type )
809
+ && !values_obj. isinstance ( & vm. ctx . types . str_type ) ;
810
+
805
811
if num_specifiers == 0 {
806
812
// literal only
807
- return if values_obj. isinstance ( & vm. ctx . types . dict_type )
808
- || ( values_obj. isinstance ( & vm. ctx . types . tuple_type )
809
- && tuple:: get_value ( & values_obj) . is_empty ( ) )
813
+ return if is_mapping
814
+ || values_obj
815
+ . payload :: < tuple:: PyTuple > ( )
816
+ . map_or ( false , |e| e. borrow_value ( ) . is_empty ( ) )
810
817
{
811
818
for ( _, part) in & self . parts {
812
819
match part {
@@ -824,7 +831,7 @@ impl CFormatString {
824
831
825
832
if mapping_required {
826
833
// dict
827
- return if values_obj . isinstance ( & vm . ctx . types . dict_type ) {
834
+ return if is_mapping {
828
835
for ( _, part) in & self . parts {
829
836
match part {
830
837
CFormatPart :: Literal ( literal) => result. push_str ( & literal) ,
@@ -845,15 +852,12 @@ impl CFormatString {
845
852
}
846
853
847
854
// tuple
848
- let values;
849
- let vec;
850
- let mut value_iter = if values_obj. isinstance ( & vm. ctx . types . tuple_type ) {
851
- values = tuple:: get_value ( & values_obj) ;
852
- values. iter ( )
855
+ let values = if let Some ( tup) = values_obj. payload_if_subclass :: < tuple:: PyTuple > ( vm) {
856
+ tup. borrow_value ( )
853
857
} else {
854
- vec = vec ! [ values_obj] ;
855
- vec. iter ( )
858
+ std:: slice:: from_ref ( & values_obj)
856
859
} ;
860
+ let mut value_iter = values. iter ( ) ;
857
861
858
862
for ( _, part) in & mut self . parts {
859
863
match part {
@@ -875,7 +879,7 @@ impl CFormatString {
875
879
}
876
880
877
881
// check that all arguments were converted
878
- if value_iter. next ( ) . is_some ( ) {
882
+ if value_iter. next ( ) . is_some ( ) && !is_mapping {
879
883
Err ( vm
880
884
. new_type_error ( "not all arguments converted during string formatting" . to_owned ( ) ) )
881
885
} else {
0 commit comments