Skip to content

Commit 366f3e2

Browse files
Merge pull request RustPython#236 from coolreader18/proper-dict
Make `dict()` work like it does in cpython
2 parents 71ba501 + 427ce43 commit 366f3e2

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

tests/snippets/dict.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
def dict_eq(d1, d2):
2+
return (all(k in d2 and d1[k] == d2[k] for k in d1)
3+
and all(k in d1 and d1[k] == d2[k] for k in d2))
4+
5+
6+
assert dict_eq(dict(a=2, b=3), {'a': 2, 'b': 3})
7+
assert dict_eq(dict({'a': 2, 'b': 3}, b=4), {'a': 2, 'b': 4})
8+
assert dict_eq(dict([('a', 2), ('b', 3)]), {'a': 2, 'b': 3})
9+
10+
a = {'g': 5}
11+
b = {'a': a, 'd': 9}
12+
c = dict(b)
13+
c['d'] = 3
14+
c['a']['g'] = 2
15+
assert dict_eq(a, {'g': 2})
16+
assert dict_eq(b, {'a': a, 'd': 9})

vm/src/obj/objdict.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::super::pyobject::{
22
PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
33
};
44
use super::super::vm::VirtualMachine;
5+
use super::objiter;
56
use super::objstr;
67
use super::objtype;
78
use num_bigint::ToBigInt;
@@ -113,8 +114,43 @@ pub fn content_contains_key_str(elements: &DictContentType, key: &str) -> bool {
113114

114115
// Python dict methods:
115116

116-
fn dict_new(_vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
117-
Ok(new(args.args[0].clone()))
117+
fn dict_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
118+
arg_check!(
119+
vm,
120+
args,
121+
required = [(_ty, Some(vm.ctx.type_type()))],
122+
optional = [(dict_obj, None)]
123+
);
124+
let dict = vm.ctx.new_dict();
125+
if let Some(dict_obj) = dict_obj {
126+
if objtype::isinstance(&dict_obj, &vm.ctx.dict_type()) {
127+
for (needle, value) in get_key_value_pairs(&dict_obj) {
128+
set_item(&dict, &needle, &value);
129+
}
130+
} else {
131+
let iter = objiter::get_iter(vm, dict_obj)?;
132+
loop {
133+
fn err(vm: &mut VirtualMachine) -> PyObjectRef {
134+
vm.new_type_error("Iterator must have exactly two elements".to_string())
135+
}
136+
let element = match objiter::get_next_object(vm, &iter)? {
137+
Some(obj) => obj,
138+
None => break,
139+
};
140+
let elem_iter = objiter::get_iter(vm, &element)?;
141+
let needle = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
142+
let value = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
143+
if let Some(_) = objiter::get_next_object(vm, &elem_iter)? {
144+
return Err(err(vm));
145+
}
146+
set_item(&dict, &needle, &value);
147+
}
148+
}
149+
}
150+
for (needle, value) in args.kwargs {
151+
set_item(&dict, &vm.new_str(needle), &value);
152+
}
153+
Ok(dict)
118154
}
119155

120156
fn dict_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

0 commit comments

Comments
 (0)