Skip to content

Commit b1361d5

Browse files
committed
Don't error on a non-dict map for cformat
1 parent 389f2bf commit b1361d5

File tree

2 files changed

+28
-28
lines changed

2 files changed

+28
-28
lines changed

vm/src/builtins/tuple.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,6 @@ impl PyTupleRef {
8282
}
8383
}
8484

85-
pub(crate) fn get_value(obj: &PyObjectRef) -> &[PyObjectRef] {
86-
obj.payload::<PyTuple>().unwrap().borrow_value()
87-
}
88-
8985
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
9086
impl PyTuple {
9187
/// Creating a new tuple with given boxed slice.

vm/src/cformat.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -652,11 +652,16 @@ impl CFormatBytes {
652652
let (num_specifiers, mapping_required) = check_specifiers(self.parts.as_slice(), vm)?;
653653
let mut result = vec![];
654654

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+
655659
if num_specifiers == 0 {
656660
// 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())
660665
{
661666
for (_, part) in &mut self.parts {
662667
match part {
@@ -674,7 +679,7 @@ impl CFormatBytes {
674679

675680
if mapping_required {
676681
// dict
677-
return if values_obj.isinstance(&vm.ctx.types.dict_type) {
682+
return if is_mapping {
678683
for (_, part) in &mut self.parts {
679684
match part {
680685
CFormatPart::Literal(literal) => result.append(literal),
@@ -695,15 +700,12 @@ impl CFormatBytes {
695700
}
696701

697702
// 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()
703705
} else {
704-
vec = vec![values_obj];
705-
vec.iter()
706+
std::slice::from_ref(&values_obj)
706707
};
708+
let mut value_iter = values.iter();
707709

708710
for (_, part) in &mut self.parts {
709711
match part {
@@ -725,7 +727,7 @@ impl CFormatBytes {
725727
}
726728

727729
// check that all arguments were converted
728-
if value_iter.next().is_some() {
730+
if value_iter.next().is_some() && !is_mapping {
729731
Err(vm
730732
.new_type_error("not all arguments converted during string formatting".to_owned()))
731733
} else {
@@ -802,11 +804,16 @@ impl CFormatString {
802804
let (num_specifiers, mapping_required) = check_specifiers(self.parts.as_slice(), vm)?;
803805
let mut result = String::new();
804806

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+
805811
if num_specifiers == 0 {
806812
// 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())
810817
{
811818
for (_, part) in &self.parts {
812819
match part {
@@ -824,7 +831,7 @@ impl CFormatString {
824831

825832
if mapping_required {
826833
// dict
827-
return if values_obj.isinstance(&vm.ctx.types.dict_type) {
834+
return if is_mapping {
828835
for (_, part) in &self.parts {
829836
match part {
830837
CFormatPart::Literal(literal) => result.push_str(&literal),
@@ -845,15 +852,12 @@ impl CFormatString {
845852
}
846853

847854
// 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()
853857
} else {
854-
vec = vec![values_obj];
855-
vec.iter()
858+
std::slice::from_ref(&values_obj)
856859
};
860+
let mut value_iter = values.iter();
857861

858862
for (_, part) in &mut self.parts {
859863
match part {
@@ -875,7 +879,7 @@ impl CFormatString {
875879
}
876880

877881
// check that all arguments were converted
878-
if value_iter.next().is_some() {
882+
if value_iter.next().is_some() && !is_mapping {
879883
Err(vm
880884
.new_type_error("not all arguments converted during string formatting".to_owned()))
881885
} else {

0 commit comments

Comments
 (0)