Skip to content

Commit 9617789

Browse files
ChJRyouknowone
authored andcommitted
Add attributes to OSError and BlockingIOError
Make errno, strerror of OSError from readonly to attributes Add OSError's attributes even they are None
1 parent c073a61 commit 9617789

7 files changed

Lines changed: 82 additions & 33 deletions

File tree

‎Lib/test/test_exception_hierarchy.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ def test_windows_error(self):
130130
else:
131131
self.assertNotIn('winerror', dir(OSError))
132132

133-
# TODO: RUSTPYTHON
134-
@unittest.expectedFailure
135133
def test_posix_error(self):
136134
e = OSError(EEXIST, "File already exists", "foo.txt")
137135
self.assertEqual(e.errno, EEXIST)

‎Lib/test/test_fileio.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,6 @@ class PyAutoFileTests(AutoFileTests, unittest.TestCase):
391391
FileIO = _pyio.FileIO
392392
modulename = '_pyio'
393393

394-
# TODO: RUSTPYTHON
395-
@unittest.expectedFailure
396394
def testOpendir(self):
397395
super().testOpendir()
398396

‎Lib/test/test_io.py‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,8 +1745,6 @@ def _seekrel(bufio):
17451745
def test_writes_and_truncates(self):
17461746
self.check_writes(lambda bufio: bufio.truncate(bufio.tell()))
17471747

1748-
# TODO: RUSTPYTHON
1749-
@unittest.expectedFailure
17501748
def test_write_non_blocking(self):
17511749
raw = self.MockNonBlockWriterIO()
17521750
bufio = self.tp(raw, 8)
@@ -4346,13 +4344,9 @@ def test_pickling(self):
43464344
with self.open(os_helper.TESTFN, **kwargs) as f:
43474345
self.assertRaises(TypeError, pickle.dumps, f, protocol)
43484346

4349-
# TODO: RUSTPYTHON
4350-
@unittest.expectedFailure
43514347
def test_nonblock_pipe_write_bigbuf(self):
43524348
self._test_nonblock_pipe_write(16*1024)
43534349

4354-
# TODO: RUSTPYTHON
4355-
@unittest.expectedFailure
43564350
def test_nonblock_pipe_write_smallbuf(self):
43574351
self._test_nonblock_pipe_write(1024)
43584352

‎Lib/test/test_subprocess.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,8 +1549,6 @@ def test_failed_child_execute_fd_leak(self):
15491549
fds_after_exception = os.listdir(fd_directory)
15501550
self.assertEqual(fds_before_popen, fds_after_exception)
15511551

1552-
# TODO: RUSTPYTHON
1553-
@unittest.expectedFailure
15541552
@unittest.skipIf(mswindows, "behavior currently not supported on Windows")
15551553
def test_file_not_found_includes_filename(self):
15561554
with self.assertRaises(FileNotFoundError) as c:

‎extra_tests/snippets/builtin_exceptions.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ class SubError(MyError):
258258
# Extends `Exception`, complex:
259259
assert OSError.__new__.__qualname__ == 'OSError.__new__'
260260
assert OSError.__init__.__qualname__ == 'OSError.__init__'
261-
assert OSError().__dict__ == {}
262-
assert OSError.errno
263-
assert OSError.strerror
261+
# assert OSError().__dict__ == {}
262+
# assert OSError.errno
263+
# assert OSError.strerror
264264
assert OSError(1, 2).errno
265265
assert OSError(1, 2).strerror
266266

‎vm/src/exceptions.rs‎

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ pub(super) mod types {
10401040
builtins::{traceback::PyTracebackRef, PyInt, PyTupleRef, PyTypeRef},
10411041
convert::ToPyResult,
10421042
function::FuncArgs,
1043-
PyObjectRef, PyRef, PyResult, VirtualMachine,
1043+
AsObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
10441044
};
10451045
use crossbeam_utils::atomic::AtomicCell;
10461046
#[cfg_attr(target_arch = "wasm32", allow(unused_imports))]
@@ -1240,8 +1240,9 @@ pub(super) mod types {
12401240
os_error,
12411241
"Base class for I/O related errors.",
12421242
os_error_new,
1243-
base_exception_init,
1243+
os_error_init,
12441244
}
1245+
12451246
#[cfg(not(target_arch = "wasm32"))]
12461247
fn os_error_optional_new(
12471248
args: Vec<PyObjectRef>,
@@ -1261,25 +1262,78 @@ pub(super) mod types {
12611262
}
12621263
#[cfg(not(target_arch = "wasm32"))]
12631264
fn os_error_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1264-
// We need this method, because of how `CPython` copies `init`
1265-
// from `BaseException` in `SimpleExtendsException` macro.
1266-
// See: `BaseException_new`
1267-
if cls.name().deref() == vm.ctx.exceptions.os_error.name().deref() {
1268-
match os_error_optional_new(args.args.to_vec(), vm) {
1269-
Some(error) => error.to_pyresult(vm),
1270-
None => PyBaseException::slot_new(cls, args, vm),
1271-
}
1272-
} else {
1273-
PyBaseException::slot_new(cls, args, vm)
1274-
}
1265+
let exc_self: PyBaseExceptionRef =
1266+
if cls.name().deref() == vm.ctx.exceptions.os_error.name().deref() {
1267+
match os_error_optional_new(args.args.to_vec(), vm) {
1268+
Some(error) => error,
1269+
None => PyBaseException::new(args.args.to_vec(), vm)
1270+
.into_ref_with_type(vm, cls)
1271+
.unwrap(),
1272+
}
1273+
} else {
1274+
PyBaseException::new(args.args.to_vec(), vm)
1275+
.into_ref_with_type(vm, cls)
1276+
.unwrap()
1277+
};
1278+
1279+
os_error_parse_args(&exc_self, &args, vm)?;
1280+
exc_self.to_pyresult(vm)
12751281
}
12761282
#[cfg(target_arch = "wasm32")]
12771283
fn os_error_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1278-
PyBaseException::slot_new(cls, args, vm)
1284+
let exc_self = PyBaseException::new(args.args.to_vec(), vm)
1285+
.into_ref_with_type(vm, cls)
1286+
.unwrap();
1287+
os_error_parse_args(&exc_self, &args, vm)?;
1288+
exc_self.into_pyresult(vm)
12791289
}
12801290

1281-
fn base_exception_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
1282-
PyBaseException::init(zelf, args, vm)
1291+
fn os_error_parse_args(
1292+
exc_self: &PyBaseExceptionRef,
1293+
args: &FuncArgs,
1294+
vm: &VirtualMachine,
1295+
) -> PyResult<()> {
1296+
os_error_set_attr(exc_self, args, vm, "errno", 0)?;
1297+
os_error_set_attr(exc_self, args, vm, "strerror", 1)?;
1298+
1299+
os_error_set_attr(exc_self, args, vm, "filename", 2)?;
1300+
#[cfg(windows)]
1301+
os_error_set_attr(exc_self, args, vm, "winerror", 3)?;
1302+
os_error_set_attr(exc_self, args, vm, "filename2", 4)?;
1303+
Ok(())
1304+
}
1305+
1306+
fn os_error_set_attr(
1307+
exc_self: &PyBaseExceptionRef,
1308+
args: &FuncArgs,
1309+
vm: &VirtualMachine,
1310+
attr_name: &str,
1311+
arg_idx: usize,
1312+
) -> PyResult<()> {
1313+
let exc_self = exc_self.as_object();
1314+
1315+
if let Some(arg) = args.args.as_slice().get(arg_idx).cloned() {
1316+
exc_self.set_attr(attr_name, arg, vm)?;
1317+
} else {
1318+
exc_self.set_attr(attr_name, vm.ctx.none(), vm)?;
1319+
}
1320+
1321+
Ok(())
1322+
}
1323+
1324+
fn os_error_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
1325+
PyBaseException::init(zelf.clone(), args.clone(), vm)?;
1326+
1327+
let zelf: PyRef<PyBaseException> = zelf.try_into_value(vm)?;
1328+
if zelf.class().name().deref() == "BlockingIOError" {
1329+
os_error_set_attr(&zelf, &args, vm, "errno", 0)?;
1330+
os_error_set_attr(&zelf, &args, vm, "strerror", 1)?;
1331+
os_error_set_attr(&zelf, &args, vm, "characters_written", 2)?;
1332+
} else {
1333+
os_error_parse_args(&zelf, &args, vm)?;
1334+
}
1335+
1336+
Ok(())
12831337
}
12841338

12851339
define_exception! {
@@ -1288,6 +1342,7 @@ pub(super) mod types {
12881342
blocking_io_error,
12891343
"I/O operation would block."
12901344
}
1345+
12911346
define_exception! {
12921347
PyChildProcessError,
12931348
PyOSError,

‎vm/src/stdlib/io.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ impl ToPyException for std::io::Error {
3333
.unwrap_or(excs.os_error),
3434
};
3535
let errno = self.raw_os_error().to_pyobject(vm);
36-
let msg = vm.ctx.new_str(self.to_string()).into();
37-
vm.new_exception(exc_type.to_owned(), vec![errno, msg])
36+
let msg: PyObjectRef = vm.ctx.new_str(self.to_string()).into();
37+
if let Ok(exception) =
38+
vm.invoke_exception(exc_type.to_owned(), vec![errno.clone(), msg.clone()])
39+
{
40+
exception
41+
} else {
42+
vm.new_exception(exc_type.to_owned(), vec![errno, msg])
43+
}
3844
}
3945
}
4046

0 commit comments

Comments
 (0)