Skip to content

Commit 65d6025

Browse files
committed
Create mappingproxy type with __getitem__ and __contains__.
1 parent dd0c70f commit 65d6025

File tree

5 files changed

+82
-0
lines changed

5 files changed

+82
-0
lines changed

tests/snippets/mappingproxy.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from testutils import assertRaises
2+
3+
class A(dict):
4+
def a():
5+
pass
6+
7+
def b():
8+
pass
9+
10+
11+
assert A.__dict__['a'] == A.a
12+
with assertRaises(KeyError):
13+
A.__dict__['not_here']
14+
15+
assert 'b' in A.__dict__
16+
assert 'c' not in A.__dict__
17+
18+
assert '__dict__' in A.__dict__

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod objint;
2020
pub mod objiter;
2121
pub mod objlist;
2222
pub mod objmap;
23+
pub mod objmappingproxy;
2324
pub mod objmemory;
2425
pub mod objmodule;
2526
pub mod objnone;

vm/src/obj/objmappingproxy.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use super::objstr::PyStringRef;
2+
use super::objtype::{self, PyClassRef};
3+
use crate::pyobject::{PyClassImpl, PyContext, PyRef, PyResult, PyValue};
4+
use crate::vm::VirtualMachine;
5+
6+
#[pyclass]
7+
#[derive(Debug)]
8+
pub struct PyMappingProxy {
9+
class: PyClassRef,
10+
}
11+
12+
pub type PyMappingProxyRef = PyRef<PyMappingProxy>;
13+
14+
impl PyValue for PyMappingProxy {
15+
fn class(vm: &VirtualMachine) -> PyClassRef {
16+
vm.ctx.mappingproxy_type.clone()
17+
}
18+
}
19+
20+
#[pyimpl]
21+
impl PyMappingProxy {
22+
pub fn new(class: PyClassRef) -> PyMappingProxy {
23+
PyMappingProxy { class }
24+
}
25+
26+
#[pymethod(name = "__getitem__")]
27+
pub fn getitem(&self, key: PyStringRef, vm: &VirtualMachine) -> PyResult {
28+
if let Some(value) = objtype::class_get_attr(&self.class, key.as_str()) {
29+
return Ok(value);
30+
}
31+
Err(vm.new_key_error(format!("Key not found: {}", key)))
32+
}
33+
34+
#[pymethod(name = "__contains__")]
35+
pub fn contains(&self, attr: PyStringRef, _vm: &VirtualMachine) -> bool {
36+
objtype::class_has_attr(&self.class, attr.as_str())
37+
}
38+
}
39+
40+
pub fn init(context: &PyContext) {
41+
PyMappingProxy::extend_class(context, &context.mappingproxy_type)
42+
}

vm/src/obj/objtype.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::vm::VirtualMachine;
1111

1212
use super::objdict::PyDictRef;
1313
use super::objlist::PyList;
14+
use super::objmappingproxy::PyMappingProxy;
1415
use super::objproperty::PropertyBuilder;
1516
use super::objstr::PyStringRef;
1617
use super::objtuple::PyTuple;
@@ -196,6 +197,11 @@ pub fn init(ctx: &PyContext) {
196197

197198
extend_class!(&ctx, &ctx.type_type, {
198199
"__call__" => ctx.new_rustfunc(type_call),
200+
"__dict__" =>
201+
PropertyBuilder::new(ctx)
202+
.add_getter(type_dict)
203+
.add_setter(type_dict_setter)
204+
.create(),
199205
"__new__" => ctx.new_rustfunc(type_new),
200206
"__mro__" =>
201207
PropertyBuilder::new(ctx)
@@ -273,6 +279,16 @@ pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMach
273279
Ok(obj)
274280
}
275281

282+
fn type_dict(class: PyClassRef, _vm: &VirtualMachine) -> PyMappingProxy {
283+
PyMappingProxy::new(class)
284+
}
285+
286+
fn type_dict_setter(_instance: PyClassRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
287+
Err(vm.new_not_implemented_error(
288+
"Setting __dict__ attribute on a type isn't yet implemented".to_string(),
289+
))
290+
}
291+
276292
// This is the internal get_attr implementation for fast lookup on a class.
277293
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
278294
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {

vm/src/pyobject.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::obj::objint::{self, PyInt, PyIntRef};
3737
use crate::obj::objiter;
3838
use crate::obj::objlist::{self, PyList};
3939
use crate::obj::objmap;
40+
use crate::obj::objmappingproxy;
4041
use crate::obj::objmemory;
4142
use crate::obj::objmodule::{self, PyModule};
4243
use crate::obj::objnone::{self, PyNone, PyNoneRef};
@@ -160,6 +161,7 @@ pub struct PyContext {
160161
pub bound_method_type: PyClassRef,
161162
pub weakref_type: PyClassRef,
162163
pub weakproxy_type: PyClassRef,
164+
pub mappingproxy_type: PyClassRef,
163165
pub object: PyClassRef,
164166
pub exceptions: exceptions::ExceptionZoo,
165167
}
@@ -292,6 +294,7 @@ impl PyContext {
292294
let range_type = create_type("range", &type_type, &object_type);
293295
let rangeiterator_type = create_type("range_iterator", &type_type, &object_type);
294296
let slice_type = create_type("slice", &type_type, &object_type);
297+
let mappingproxy_type = create_type("mappingproxy", &type_type, &object_type);
295298
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type);
296299

297300
fn create_object<T: PyObjectPayload>(payload: T, cls: &PyClassRef) -> PyRef<T> {
@@ -358,6 +361,7 @@ impl PyContext {
358361
function_type,
359362
builtin_function_or_method_type,
360363
super_type,
364+
mappingproxy_type,
361365
property_type,
362366
readonly_property_type,
363367
generator_type,
@@ -403,6 +407,7 @@ impl PyContext {
403407
objweakproxy::init(&context);
404408
objnone::init(&context);
405409
objmodule::init(&context);
410+
objmappingproxy::init(&context);
406411
exceptions::init(&context);
407412
context
408413
}

0 commit comments

Comments
 (0)