Skip to content

Commit 3fbf627

Browse files
committed
Merge branch 'master' into scope_globals_locals
2 parents 4a82c8f + 9e5b76c commit 3fbf627

39 files changed

+1312
-1261
lines changed

tests/snippets/builtin_open.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
assert 'RustPython' in fd.read()
55

66
assert_raises(FileNotFoundError, lambda: open('DoesNotExist'))
7+
8+
# Use open as a context manager
9+
with open('README.md') as fp:
10+
fp.read()

tests/snippets/class.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,6 @@ def square(self):
1616
assert foo.square() == 25
1717

1818

19-
class Fubar:
20-
def __init__(self):
21-
self.x = 100
22-
23-
@property
24-
def foo(self):
25-
value = self.x
26-
self.x += 1
27-
return value
28-
29-
30-
f = Fubar()
31-
assert f.foo == 100
32-
assert f.foo == 101
33-
34-
3519
class Bar:
3620
""" W00t """
3721
def __init__(self, x):

tests/snippets/property.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from testutils import assertRaises
2+
3+
4+
class Fubar:
5+
def __init__(self):
6+
self.x = 100
7+
8+
@property
9+
def foo(self):
10+
value = self.x
11+
self.x += 1
12+
return value
13+
14+
15+
f = Fubar()
16+
assert f.foo == 100
17+
assert f.foo == 101
18+
19+
20+
null_property = property()
21+
assert type(null_property) is property
22+
23+
p = property(lambda x: x[0])
24+
assert p.__get__((2,), tuple) == 2
25+
# TODO owner parameter is optional
26+
# assert p.__get__((2,)) == 2
27+
28+
with assertRaises(AttributeError):
29+
null_property.__get__((), tuple)
30+
31+
with assertRaises(TypeError):
32+
property.__new__(object)

tests/snippets/stdlib_socket.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,29 @@
2929
with assertRaises(TypeError):
3030
s.connect(("127.0.0.1", 8888, 8888))
3131

32+
with assertRaises(OSError):
33+
# Lets hope nobody is listening on port 1
34+
s.connect(("127.0.0.1", 1))
35+
3236
with assertRaises(TypeError):
3337
s.bind(("127.0.0.1", 8888, 8888))
3438

39+
with assertRaises(OSError):
40+
# Lets hope nobody run this test on machine with ip 1.2.3.4
41+
s.bind(("1.2.3.4", 8888))
42+
3543
with assertRaises(TypeError):
3644
s.bind((888, 8888))
3745

46+
s.close()
47+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
48+
s.bind(("127.0.0.1", 0))
49+
with assertRaises(OSError):
50+
s.recv(100)
51+
52+
with assertRaises(OSError):
53+
s.send(MESSAGE_A)
54+
3855
s.close()
3956

4057
# UDP
@@ -73,3 +90,15 @@
7390
assert recv_b == MESSAGE_B
7491
sock1.close()
7592
sock3.close()
93+
94+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
95+
with assertRaises(OSError):
96+
s.bind(("1.2.3.4", 888))
97+
98+
s.close()
99+
### Errors
100+
with assertRaises(OSError):
101+
socket.socket(100, socket.SOCK_STREAM)
102+
103+
with assertRaises(OSError):
104+
socket.socket(socket.AF_INET, 1000)

tests/snippets/type_hints.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11

22
# See also: https://github.com/RustPython/RustPython/issues/587
33

4-
def curry(foo: int, bla=2) -> float:
4+
def curry(foo: int, bla: int =2) -> float:
55
return foo * 3.1415926 * bla
66

77
assert curry(2) > 10
8+
9+
print(curry.__annotations__)
10+
assert curry.__annotations__['foo'] is int
11+
assert curry.__annotations__['return'] is float
12+
assert curry.__annotations__['bla'] is int

vm/src/builtins.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
805805
"StopIteration" => ctx.exceptions.stop_iteration.clone(),
806806
"ZeroDivisionError" => ctx.exceptions.zero_division_error.clone(),
807807
"KeyError" => ctx.exceptions.key_error.clone(),
808+
"OSError" => ctx.exceptions.os_error.clone(),
808809
});
809810

810811
#[cfg(not(target_arch = "wasm32"))]

vm/src/frame.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ use crate::builtins;
1111
use crate::bytecode;
1212
use crate::import::{import, import_module};
1313
use crate::obj::objbool;
14+
use crate::obj::objbuiltinfunc::PyBuiltinFunction;
1415
use crate::obj::objcode;
1516
use crate::obj::objdict;
1617
use crate::obj::objdict::PyDict;
1718
use crate::obj::objint::PyInt;
1819
use crate::obj::objiter;
1920
use crate::obj::objlist;
21+
use crate::obj::objslice::PySlice;
2022
use crate::obj::objstr;
2123
use crate::obj::objtype;
2224
use crate::pyobject::{
23-
DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef,
24-
PyResult, TypeProtocol,
25+
DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2,
26+
PyObjectRef, PyResult, TryFromObject, TypeProtocol,
2527
};
2628
use crate::vm::VirtualMachine;
2729

@@ -179,6 +181,12 @@ pub struct Frame {
179181
pub lasti: RefCell<usize>, // index of last instruction ran
180182
}
181183

184+
impl PyObjectPayload2 for Frame {
185+
fn required_type(ctx: &PyContext) -> PyObjectRef {
186+
ctx.frame_type()
187+
}
188+
}
189+
182190
// Running a frame can result in one of the below:
183191
pub enum ExecutionResult {
184192
Return(PyObjectRef),
@@ -242,14 +250,7 @@ impl Frame {
242250
vm.ctx.new_int(lineno.get_row()),
243251
vm.ctx.new_str(run_obj_name.clone()),
244252
]);
245-
objlist::list_append(
246-
vm,
247-
PyFuncArgs {
248-
args: vec![traceback, pos],
249-
kwargs: vec![],
250-
},
251-
)
252-
.unwrap();
253+
objlist::PyListRef::try_from_object(vm, traceback)?.append(pos, vm);
253254
// exception.__trace
254255
match self.unwind_exception(vm, exception) {
255256
None => {}
@@ -407,7 +408,9 @@ impl Frame {
407408
let step = if out.len() == 3 { out[2].take() } else { None };
408409

409410
let obj = PyObject::new(
410-
PyObjectPayload::Slice { start, stop, step },
411+
PyObjectPayload::AnyRustValue {
412+
value: Box::new(PySlice { start, stop, step }),
413+
},
411414
vm.ctx.slice_type(),
412415
);
413416
self.push_value(obj);
@@ -416,13 +419,7 @@ impl Frame {
416419
bytecode::Instruction::ListAppend { i } => {
417420
let list_obj = self.nth_value(*i);
418421
let item = self.pop_value();
419-
objlist::list_append(
420-
vm,
421-
PyFuncArgs {
422-
args: vec![list_obj.clone(), item],
423-
kwargs: vec![],
424-
},
425-
)?;
422+
objlist::PyListRef::try_from_object(vm, list_obj)?.append(item, vm);
426423
Ok(None)
427424
}
428425
bytecode::Instruction::SetAdd { i } => {
@@ -557,7 +554,7 @@ impl Frame {
557554
let _qualified_name = self.pop_value();
558555
let code_obj = self.pop_value();
559556

560-
let _annotations = if flags.contains(bytecode::FunctionOpArg::HAS_ANNOTATIONS) {
557+
let annotations = if flags.contains(bytecode::FunctionOpArg::HAS_ANNOTATIONS) {
561558
self.pop_value()
562559
} else {
563560
vm.new_dict()
@@ -574,13 +571,8 @@ impl Frame {
574571
let scope = self.scope.clone();
575572
let obj = vm.ctx.new_function(code_obj, scope, defaults);
576573

577-
let annotation_repr = vm.to_pystr(&_annotations)?;
574+
vm.ctx.set_attr(&obj, "__annotations__", annotations);
578575

579-
warn!(
580-
"Type annotation must be stored in attribute! {:?}",
581-
annotation_repr
582-
);
583-
// TODO: use annotations with set_attr here!
584576
self.push_value(obj);
585577
Ok(None)
586578
}
@@ -714,8 +706,10 @@ impl Frame {
714706
}
715707
bytecode::Instruction::LoadBuildClass => {
716708
let rustfunc = PyObject::new(
717-
PyObjectPayload::RustFunction {
718-
function: Box::new(builtins::builtin_build_class_),
709+
PyObjectPayload::AnyRustValue {
710+
value: Box::new(PyBuiltinFunction::new(Box::new(
711+
builtins::builtin_build_class_,
712+
))),
719713
},
720714
vm.ctx.type_type(),
721715
);

vm/src/function.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
33
use std::ops::Deref;
44

55
use crate::obj::objtype;
6+
use crate::obj::objtype::PyClassRef;
67
use crate::pyobject::{
78
IntoPyObject, PyContext, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
89
TryFromObject, TypeProtocol,
@@ -44,6 +45,32 @@ where
4445
_payload: PhantomData,
4546
}
4647
}
48+
49+
pub fn new_with_type(vm: &mut VirtualMachine, payload: T, cls: PyClassRef) -> PyResult<Self> {
50+
let required_type = T::required_type(&vm.ctx);
51+
if objtype::issubclass(&cls.obj, &required_type) {
52+
Ok(PyRef {
53+
obj: PyObject::new(
54+
PyObjectPayload::AnyRustValue {
55+
value: Box::new(payload),
56+
},
57+
cls.obj,
58+
),
59+
_payload: PhantomData,
60+
})
61+
} else {
62+
let subtype = vm.to_pystr(&cls.obj)?;
63+
let basetype = vm.to_pystr(&required_type)?;
64+
Err(vm.new_type_error(format!("{} is not a subtype of {}", subtype, basetype)))
65+
}
66+
}
67+
68+
pub fn as_object(&self) -> &PyObjectRef {
69+
&self.obj
70+
}
71+
pub fn into_object(self) -> PyObjectRef {
72+
self.obj
73+
}
4774
}
4875

4976
impl<T> Deref for PyRef<T>

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! This package contains the python basic/builtin types
22
33
pub mod objbool;
4+
pub mod objbuiltinfunc;
45
pub mod objbytearray;
56
pub mod objbytes;
67
pub mod objcode;

vm/src/obj/objbuiltinfunc.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::fmt;
2+
3+
use crate::pyobject::{PyContext, PyNativeFunc, PyObjectPayload2, PyObjectRef};
4+
5+
pub struct PyBuiltinFunction {
6+
// TODO: shouldn't be public
7+
pub value: PyNativeFunc,
8+
}
9+
10+
impl PyObjectPayload2 for PyBuiltinFunction {
11+
fn required_type(ctx: &PyContext) -> PyObjectRef {
12+
ctx.builtin_function_or_method_type()
13+
}
14+
}
15+
16+
impl fmt::Debug for PyBuiltinFunction {
17+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18+
write!(f, "builtin function")
19+
}
20+
}
21+
22+
impl PyBuiltinFunction {
23+
pub fn new(value: PyNativeFunc) -> Self {
24+
Self { value }
25+
}
26+
}

vm/src/obj/objbytes.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::ops::Deref;
55
use super::objint;
66
use super::objtype;
77
use crate::pyobject::{
8-
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
9-
TypeProtocol,
8+
PyContext, PyFuncArgs, PyIteratorValue, PyObject, PyObjectPayload, PyObjectPayload2,
9+
PyObjectRef, PyResult, TypeProtocol,
1010
};
1111
use crate::vm::VirtualMachine;
1212
use num_traits::ToPrimitive;
@@ -209,9 +209,11 @@ fn bytes_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
209209
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]);
210210

211211
let iter_obj = PyObject::new(
212-
PyObjectPayload::Iterator {
213-
position: Cell::new(0),
214-
iterated_obj: obj.clone(),
212+
PyObjectPayload::AnyRustValue {
213+
value: Box::new(PyIteratorValue {
214+
position: Cell::new(0),
215+
iterated_obj: obj.clone(),
216+
}),
215217
},
216218
vm.ctx.iter_type(),
217219
);

vm/src/obj/objcode.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn init(context: &PyContext) {
4747
("co_kwonlyargcount", code_co_kwonlyargcount),
4848
("co_name", code_co_name),
4949
] {
50-
context.set_attr(code_type, name, context.new_member_descriptor(f))
50+
context.set_attr(code_type, name, context.new_property(f))
5151
}
5252
}
5353

@@ -79,14 +79,7 @@ fn code_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7979
}
8080

8181
fn member_code_obj(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult<bytecode::CodeObject> {
82-
arg_check!(
83-
vm,
84-
args,
85-
required = [
86-
(zelf, Some(vm.ctx.code_type())),
87-
(_cls, Some(vm.ctx.type_type()))
88-
]
89-
);
82+
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.code_type()))]);
9083
Ok(get_value(zelf))
9184
}
9285

0 commit comments

Comments
 (0)