Skip to content

Commit 31523fe

Browse files
Merge pull request RustPython#265 from rmliddle/implement-io
File-IO: IO Module and Open Builtin
2 parents d627230 + deb0688 commit 31523fe

File tree

12 files changed

+559
-14
lines changed

12 files changed

+559
-14
lines changed

tests/snippets/buffered_reader.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from io import BufferedReader, FileIO
2+
3+
fi = FileIO('README.md')
4+
bb = BufferedReader(fi)
5+
6+
result = bb.read()
7+
8+
assert len(result) <= 8*1024
9+
assert len(result) >= 0
10+
assert isinstance(result, bytes)

tests/snippets/os_open.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import os
2+
3+
assert os.open('README.md', 0) > 0
4+

tests/snippets/os_static.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import os
2+
3+
assert os.O_RDONLY == 0
4+
assert os.O_WRONLY == 1
5+
assert os.O_RDWR == 2

vm/src/builtins.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ use super::obj::objint;
1313
use super::obj::objiter;
1414
use super::obj::objstr;
1515
use super::obj::objtype;
16+
1617
use super::pyobject::{
1718
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef,
1819
PyResult, Scope, TypeProtocol,
1920
};
21+
use super::stdlib::io::io_open;
22+
2023
use super::vm::VirtualMachine;
2124
use num_bigint::ToBigInt;
2225
use num_traits::{Signed, ToPrimitive, Zero};
@@ -499,8 +502,6 @@ fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
499502
Ok(x)
500503
}
501504

502-
// builtin_memoryview
503-
504505
fn builtin_min(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
505506
let candidates = if args.args.len() > 1 {
506507
args.args.clone()
@@ -587,8 +588,6 @@ fn builtin_oct(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
587588
Ok(vm.new_str(s))
588589
}
589590

590-
// builtin_open
591-
592591
fn builtin_ord(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
593592
arg_check!(vm, args, required = [(string, Some(vm.ctx.str_type()))]);
594593
let string = objstr::get_value(string);
@@ -771,9 +770,11 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
771770
ctx.set_attr(&py_mod, "locals", ctx.new_rustfunc(builtin_locals));
772771
ctx.set_attr(&py_mod, "map", ctx.new_rustfunc(builtin_map));
773772
ctx.set_attr(&py_mod, "max", ctx.new_rustfunc(builtin_max));
773+
ctx.set_attr(&py_mod, "memoryview", ctx.memoryview_type());
774774
ctx.set_attr(&py_mod, "min", ctx.new_rustfunc(builtin_min));
775775
ctx.set_attr(&py_mod, "object", ctx.object());
776776
ctx.set_attr(&py_mod, "oct", ctx.new_rustfunc(builtin_oct));
777+
ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(io_open));
777778
ctx.set_attr(&py_mod, "ord", ctx.new_rustfunc(builtin_ord));
778779
ctx.set_attr(&py_mod, "next", ctx.new_rustfunc(builtin_next));
779780
ctx.set_attr(&py_mod, "pow", ctx.new_rustfunc(builtin_pow));

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod objgenerator;
1313
pub mod objint;
1414
pub mod objiter;
1515
pub mod objlist;
16+
pub mod objmemory;
1617
pub mod objobject;
1718
pub mod objproperty;
1819
pub mod objsequence;

vm/src/obj/objbytearray.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
use super::super::pyobject::{
44
PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
55
};
6+
7+
use super::objint;
8+
69
use super::super::vm::VirtualMachine;
710
use super::objbytes::get_value;
8-
use super::objint;
911
use super::objtype;
12+
use num_bigint::ToBigInt;
1013
use num_traits::ToPrimitive;
14+
1115
// Binary data support
1216

1317
/// Fill bytearray class methods dictionary.
@@ -28,6 +32,11 @@ pub fn init(context: &PyContext) {
2832
"__repr__",
2933
context.new_rustfunc(bytearray_repr),
3034
);
35+
context.set_attr(
36+
&bytearray_type,
37+
"__len__",
38+
context.new_rustfunc(bytesarray_len),
39+
);
3140
}
3241

3342
fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -54,13 +63,20 @@ fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5463
} else {
5564
vec![]
5665
};
57-
5866
Ok(PyObject::new(
5967
PyObjectKind::Bytes { value: value },
6068
cls.clone(),
6169
))
6270
}
6371

72+
fn bytesarray_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
73+
arg_check!(vm, args, required = [(a, Some(vm.ctx.bytearray_type()))]);
74+
75+
let byte_vec = get_value(a).to_vec();
76+
let value = byte_vec.len().to_bigint();
77+
Ok(vm.ctx.new_int(value.unwrap()))
78+
}
79+
6480
fn bytearray_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6581
arg_check!(
6682
vm,
@@ -95,8 +111,7 @@ fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
95111

96112
fn bytearray_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
97113
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]);
98-
let data = get_value(obj);
99-
let data: Vec<String> = data.iter().map(|b| format!("\\x{:02x}", b)).collect();
100-
let data = data.join("");
114+
let value = get_value(obj);
115+
let data = String::from_utf8(value.to_vec()).unwrap();
101116
Ok(vm.new_str(format!("bytearray(b'{}')", data)))
102117
}

vm/src/obj/objbytes.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use num_traits::ToPrimitive;
99
use std::cell::Ref;
1010
use std::hash::{Hash, Hasher};
1111
use std::ops::Deref;
12+
1213
// Binary data support
1314

1415
// Fill bytes class methods:
@@ -18,6 +19,7 @@ pub fn init(context: &PyContext) {
1819
context.set_attr(bytes_type, "__hash__", context.new_rustfunc(bytes_hash));
1920
context.set_attr(bytes_type, "__new__", context.new_rustfunc(bytes_new));
2021
context.set_attr(bytes_type, "__repr__", context.new_rustfunc(bytes_repr));
22+
context.set_attr(bytes_type, "__len__", context.new_rustfunc(bytes_len));
2123
}
2224

2325
fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -66,6 +68,14 @@ fn bytes_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6668
Ok(vm.ctx.new_bool(result))
6769
}
6870

71+
fn bytes_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
72+
arg_check!(vm, args, required = [(a, Some(vm.ctx.bytes_type()))]);
73+
74+
let byte_vec = get_value(a).to_vec();
75+
let value = byte_vec.len().to_bigint();
76+
Ok(vm.ctx.new_int(value.unwrap()))
77+
}
78+
6979
fn bytes_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7080
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytes_type()))]);
7181
let data = get_value(zelf);

vm/src/obj/objmemory.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use super::objtype;
2+
3+
use super::super::pyobject::{
4+
PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
5+
};
6+
use super::super::vm::VirtualMachine;
7+
8+
pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9+
arg_check!(vm, args, required = [(cls, None), (bytes_object, None)]);
10+
vm.ctx.set_attr(&cls, "obj", bytes_object.clone());
11+
Ok(PyObject::new(
12+
PyObjectKind::MemoryView {
13+
obj: bytes_object.clone(),
14+
},
15+
cls.clone(),
16+
))
17+
}
18+
19+
pub fn init(ctx: &PyContext) {
20+
let ref memoryview_type = ctx.memoryview_type;
21+
ctx.set_attr(
22+
&memoryview_type,
23+
"__new__",
24+
ctx.new_rustfunc(new_memory_view),
25+
);
26+
}

vm/src/pyobject.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use super::obj::objgenerator;
1414
use super::obj::objint;
1515
use super::obj::objiter;
1616
use super::obj::objlist;
17+
use super::obj::objmemory;
1718
use super::obj::objobject;
1819
use super::obj::objproperty;
1920
use super::obj::objset;
@@ -114,6 +115,7 @@ pub struct PyContext {
114115
pub true_value: PyObjectRef,
115116
pub false_value: PyObjectRef,
116117
pub list_type: PyObjectRef,
118+
pub memoryview_type: PyObjectRef,
117119
pub none: PyObjectRef,
118120
pub tuple_type: PyObjectRef,
119121
pub set_type: PyObjectRef,
@@ -197,6 +199,7 @@ impl PyContext {
197199
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
198200
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
199201
let bool_type = create_type("bool", &type_type, &int_type, &dict_type);
202+
let memoryview_type = create_type("memoryview", &type_type, &object_type, &dict_type);
200203
let code_type = create_type("code", &type_type, &int_type, &dict_type);
201204
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
202205

@@ -217,6 +220,7 @@ impl PyContext {
217220
);
218221
let context = PyContext {
219222
bool_type: bool_type,
223+
memoryview_type: memoryview_type,
220224
bytearray_type: bytearray_type,
221225
bytes_type: bytes_type,
222226
code_type: code_type,
@@ -261,6 +265,7 @@ impl PyContext {
261265
objbytes::init(&context);
262266
objbytearray::init(&context);
263267
objproperty::init(&context);
268+
objmemory::init(&context);
264269
objstr::init(&context);
265270
objsuper::init(&context);
266271
objtuple::init(&context);
@@ -320,6 +325,10 @@ impl PyContext {
320325
self.bool_type.clone()
321326
}
322327

328+
pub fn memoryview_type(&self) -> PyObjectRef {
329+
self.memoryview_type.clone()
330+
}
331+
323332
pub fn tuple_type(&self) -> PyObjectRef {
324333
self.tuple_type.clone()
325334
}
@@ -402,6 +411,10 @@ impl PyContext {
402411
PyObject::new(PyObjectKind::Bytes { value: data }, self.bytes_type())
403412
}
404413

414+
pub fn new_bytearray(&self, data: Vec<u8>) -> PyObjectRef {
415+
PyObject::new(PyObjectKind::Bytes { value: data }, self.bytearray_type())
416+
}
417+
405418
pub fn new_bool(&self, b: bool) -> PyObjectRef {
406419
if b {
407420
self.true_value.clone()
@@ -753,6 +766,20 @@ impl DictProtocol for PyObjectRef {
753766
}
754767
}
755768

769+
pub trait BufferProtocol {
770+
fn readonly(&self) -> bool;
771+
}
772+
773+
impl BufferProtocol for PyObjectRef {
774+
fn readonly(&self) -> bool {
775+
match objtype::get_type_name(&self.typ()).as_ref() {
776+
"bytes" => false,
777+
"bytearray" | "memoryview" => true,
778+
_ => panic!("Bytes-Like type expected not {:?}", self),
779+
}
780+
}
781+
}
782+
756783
impl fmt::Debug for PyObject {
757784
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
758785
write!(f, "[PyObj {:?}]", self.kind)
@@ -850,6 +877,9 @@ pub enum PyObjectKind {
850877
stop: Option<i32>,
851878
step: Option<i32>,
852879
},
880+
MemoryView {
881+
obj: PyObjectRef,
882+
},
853883
Code {
854884
code: bytecode::CodeObject,
855885
},
@@ -900,6 +930,7 @@ impl fmt::Debug for PyObjectKind {
900930
&PyObjectKind::Float { ref value } => write!(f, "float {}", value),
901931
&PyObjectKind::Complex { ref value } => write!(f, "complex {}", value),
902932
&PyObjectKind::Bytes { ref value } => write!(f, "bytes/bytearray {:?}", value),
933+
&PyObjectKind::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj),
903934
&PyObjectKind::Sequence { elements: _ } => write!(f, "list or tuple"),
904935
&PyObjectKind::Dict { elements: _ } => write!(f, "dict"),
905936
&PyObjectKind::Set { elements: _ } => write!(f, "set"),
@@ -953,6 +984,7 @@ impl PyObject {
953984
PyObjectKind::Float { ref value } => format!("{:?}", value),
954985
PyObjectKind::Complex { ref value } => format!("{:?}", value),
955986
PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value),
987+
PyObjectKind::MemoryView { ref obj } => format!("b'{:?}'", obj),
956988
PyObjectKind::Sequence { ref elements } => format!(
957989
"(/[{}]/)",
958990
elements

0 commit comments

Comments
 (0)