Skip to content

Commit 8522739

Browse files
committed
Integrate OSError creations into OSErrorBuilder
1 parent b35e1a8 commit 8522739

File tree

6 files changed

+166
-109
lines changed

6 files changed

+166
-109
lines changed

crates/vm/src/exceptions.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,8 @@ pub(crate) fn errno_to_exc_type(_errno: i32, _vm: &VirtualMachine) -> Option<&'s
11931193
None
11941194
}
11951195

1196+
pub(crate) use types::{OSErrorBuilder, ToOSErrorBuilder};
1197+
11961198
pub(super) mod types {
11971199
use crate::common::lock::PyRwLock;
11981200
use crate::object::{MaybeTraverse, Traverse, TraverseFn};
@@ -1204,14 +1206,143 @@ pub(super) mod types {
12041206
PyInt, PyStrRef, PyTupleRef, PyType, PyTypeRef, traceback::PyTracebackRef,
12051207
tuple::IntoPyTuple,
12061208
},
1209+
convert::ToPyObject,
12071210
convert::ToPyResult,
12081211
function::{ArgBytesLike, FuncArgs},
1212+
ospath::OsPathOrFd,
12091213
types::{Constructor, Initializer},
12101214
};
12111215
use crossbeam_utils::atomic::AtomicCell;
12121216
use itertools::Itertools;
12131217
use rustpython_common::str::UnicodeEscapeCodepoint;
12141218

1219+
pub(crate) trait ToOSErrorBuilder {
1220+
fn to_os_error_builder<'a>(&self, vm: &VirtualMachine) -> OSErrorBuilder;
1221+
}
1222+
1223+
pub struct OSErrorBuilder {
1224+
exc_type: PyTypeRef,
1225+
errno: Option<i32>,
1226+
strerror: Option<PyObjectRef>,
1227+
filename: Option<PyObjectRef>,
1228+
filename2: Option<PyObjectRef>,
1229+
#[cfg(windows)]
1230+
winerror: Option<i32>,
1231+
}
1232+
1233+
impl OSErrorBuilder {
1234+
#[must_use]
1235+
pub fn with_subtype(
1236+
exc_type: PyTypeRef,
1237+
errno: Option<i32>,
1238+
strerror: impl ToPyObject,
1239+
vm: &VirtualMachine,
1240+
) -> Self {
1241+
let strerror = strerror.to_pyobject(vm);
1242+
Self {
1243+
exc_type,
1244+
errno: errno,
1245+
strerror: Some(strerror.to_pyobject(vm)),
1246+
filename: None,
1247+
filename2: None,
1248+
#[cfg(windows)]
1249+
winerror: None,
1250+
}
1251+
}
1252+
#[must_use]
1253+
pub fn with_errno(errno: i32, strerror: impl ToPyObject, vm: &VirtualMachine) -> Self {
1254+
let exc_type = crate::exceptions::errno_to_exc_type(errno, vm)
1255+
.unwrap_or(vm.ctx.exceptions.os_error)
1256+
.to_owned();
1257+
Self::with_subtype(exc_type, Some(errno), strerror, vm)
1258+
}
1259+
1260+
// #[must_use]
1261+
// pub(crate) fn errno(mut self, errno: i32) -> Self {
1262+
// self.errno.replace(errno);
1263+
// self
1264+
// }
1265+
1266+
#[must_use]
1267+
pub(crate) fn filename(mut self, filename: PyObjectRef) -> Self {
1268+
let filename = filename.into();
1269+
self.filename.replace(filename);
1270+
self
1271+
}
1272+
1273+
#[must_use]
1274+
pub(crate) fn filename2(mut self, filename: PyObjectRef) -> Self {
1275+
let filename = filename.into();
1276+
self.filename2.replace(filename);
1277+
self
1278+
}
1279+
1280+
// #[must_use]
1281+
// #[cfg(windows)]
1282+
// pub(crate) fn winerror(mut self, filename: PyObjectRef) -> Self {
1283+
// let filename = filename.into();
1284+
// self.winerror.replace(filename);
1285+
// self
1286+
// }
1287+
1288+
#[must_use]
1289+
pub(crate) fn with_filename<'a>(
1290+
error: &std::io::Error,
1291+
filename: impl Into<OsPathOrFd<'a>>,
1292+
vm: &VirtualMachine,
1293+
) -> PyBaseExceptionRef {
1294+
// TODO: return type to PyRef<PyOSError>
1295+
let builder = error.to_os_error_builder(vm);
1296+
let builder = builder.filename(filename.into().filename(vm));
1297+
builder.build(vm).upcast()
1298+
}
1299+
1300+
pub fn build(self, vm: &VirtualMachine) -> PyRef<PyOSError> {
1301+
let OSErrorBuilder {
1302+
exc_type,
1303+
errno,
1304+
strerror,
1305+
filename,
1306+
#[cfg(windows)]
1307+
winerror,
1308+
filename2,
1309+
} = self;
1310+
1311+
#[cfg(windows)]
1312+
let winerror = winerror.to_pyobject(vm);
1313+
#[cfg(not(windows))]
1314+
let winerror = vm.ctx.none();
1315+
1316+
let args = vec![
1317+
errno.to_pyobject(vm),
1318+
strerror.to_pyobject(vm),
1319+
filename.to_pyobject(vm),
1320+
winerror,
1321+
filename2.to_pyobject(vm),
1322+
];
1323+
1324+
let payload =
1325+
PyOSError::py_new(&exc_type, args.into(), vm).expect("new_os_error usage error");
1326+
// unsafe {
1327+
// let _ = payload.filename.swap(filename);
1328+
// let _ = payload.filename2.swap(filename2);
1329+
// }
1330+
// #[cfg(windows)]
1331+
// {
1332+
// let _ = payload.winerror.swap(winerror);
1333+
// }
1334+
payload
1335+
.into_ref_with_type(vm, exc_type)
1336+
.expect("new_os_error usage error")
1337+
}
1338+
}
1339+
1340+
impl crate::convert::IntoPyException for OSErrorBuilder {
1341+
fn into_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1342+
self.build(vm).upcast()
1343+
}
1344+
}
1345+
12151346
// Re-export exception group types from dedicated module
12161347
pub use crate::exception_group::types::PyBaseExceptionGroup;
12171348

crates/vm/src/ospath.rs

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ use rustpython_common::crt_fd;
22

33
use crate::{
44
PyObjectRef, PyResult, VirtualMachine,
5-
builtins::PyBaseExceptionRef,
65
convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject},
76
function::FsPath,
8-
object::AsObject,
97
};
108
use std::path::{Path, PathBuf};
119

@@ -143,63 +141,3 @@ impl OsPathOrFd<'_> {
143141
}
144142
}
145143
}
146-
147-
// TODO: preserve the input `PyObjectRef` of filename and filename2 (Failing check `self.assertIs(err.filename, name, str(func)`)
148-
pub struct OSErrorBuilder<'a> {
149-
error: &'a std::io::Error,
150-
filename: Option<OsPathOrFd<'a>>,
151-
filename2: Option<OsPathOrFd<'a>>,
152-
}
153-
154-
impl<'a> OSErrorBuilder<'a> {
155-
pub const fn new(error: &'a std::io::Error) -> Self {
156-
Self {
157-
error,
158-
filename: None,
159-
filename2: None,
160-
}
161-
}
162-
163-
pub(crate) fn filename(mut self, filename: impl Into<OsPathOrFd<'a>>) -> Self {
164-
let filename = filename.into();
165-
self.filename.replace(filename);
166-
self
167-
}
168-
169-
pub(crate) fn filename2(mut self, filename: impl Into<OsPathOrFd<'a>>) -> Self {
170-
let filename = filename.into();
171-
self.filename2.replace(filename);
172-
self
173-
}
174-
175-
pub(crate) fn with_filename(
176-
error: &'a std::io::Error,
177-
filename: impl Into<OsPathOrFd<'a>>,
178-
vm: &VirtualMachine,
179-
) -> PyBaseExceptionRef {
180-
let zelf = OSErrorBuilder {
181-
error,
182-
filename: Some(filename.into()),
183-
filename2: None,
184-
};
185-
zelf.to_pyexception(vm)
186-
}
187-
}
188-
189-
impl ToPyException for OSErrorBuilder<'_> {
190-
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
191-
let exc = self.error.to_pyexception(vm);
192-
193-
if let Some(filename) = &self.filename {
194-
exc.as_object()
195-
.set_attr("filename", filename.filename(vm), vm)
196-
.unwrap();
197-
}
198-
if let Some(filename2) = &self.filename2 {
199-
exc.as_object()
200-
.set_attr("filename2", filename2.filename(vm), vm)
201-
.unwrap();
202-
}
203-
exc
204-
}
205-
}

crates/vm/src/stdlib/io.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ use crate::{
1414
builtins::{PyBaseExceptionRef, PyModule},
1515
common::os::ErrorExt,
1616
convert::{IntoPyException, ToPyException},
17+
exceptions::{OSErrorBuilder, ToOSErrorBuilder},
1718
};
1819
pub use _io::{OpenArgs, io_open as open};
1920

20-
impl ToPyException for std::io::Error {
21-
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
21+
impl ToOSErrorBuilder for std::io::Error {
22+
fn to_os_error_builder(&self, vm: &VirtualMachine) -> OSErrorBuilder {
2223
let errno = self.posix_errno();
2324
#[cfg(windows)]
2425
let msg = 'msg: {
@@ -53,23 +54,24 @@ impl ToPyException for std::io::Error {
5354
#[cfg(not(any(windows, unix)))]
5455
let msg = self.to_string();
5556

56-
#[allow(clippy::let_and_return)]
57-
let exc = vm.new_errno_error(errno, msg);
57+
#[allow(unused_mut)]
58+
let mut builder = OSErrorBuilder::with_errno(errno, msg, vm);
59+
5860
#[cfg(windows)]
5961
{
60-
use crate::object::AsObject;
6162
let winerror = if let Some(winerror) = self.raw_os_error() {
62-
vm.new_pyobj(winerror)
63-
} else {
64-
vm.ctx.none()
63+
builder = builder.winerror(winerror);
6564
};
66-
67-
// FIXME: manual setup winerror due to lack of OSError.__init__ support
68-
exc.as_object()
69-
.set_attr("winerror", vm.new_pyobj(winerror), vm)
70-
.unwrap();
7165
}
72-
exc.upcast()
66+
67+
builder
68+
}
69+
}
70+
71+
impl ToPyException for std::io::Error {
72+
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
73+
let builder = self.to_os_error_builder(vm);
74+
builder.into_pyexception(vm)
7375
}
7476
}
7577

@@ -4328,8 +4330,9 @@ mod fileio {
43284330
builtins::{PyBaseExceptionRef, PyUtf8Str, PyUtf8StrRef},
43294331
common::crt_fd,
43304332
convert::{IntoPyException, ToPyException},
4333+
exceptions::OSErrorBuilder,
43314334
function::{ArgBytesLike, ArgMemoryBuffer, OptionalArg, OptionalOption},
4332-
ospath::{OSErrorBuilder, OsPath, OsPathOrFd},
4335+
ospath::{OsPath, OsPathOrFd},
43334336
stdlib::os,
43344337
types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
43354338
};

crates/vm/src/stdlib/os.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub(super) mod _os {
153153
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
154154
builtins::{
155155
PyBytesRef, PyGenericAlias, PyIntRef, PyStrRef, PyTuple, PyTupleRef, PyTypeRef,
156+
ToOSErrorBuilder,
156157
},
157158
common::{
158159
crt_fd,
@@ -161,8 +162,9 @@ pub(super) mod _os {
161162
suppress_iph,
162163
},
163164
convert::{IntoPyException, ToPyObject},
165+
exceptions::OSErrorBuilder,
164166
function::{ArgBytesLike, FsPath, FuncArgs, OptionalArg},
165-
ospath::{OSErrorBuilder, OsPath, OsPathOrFd, OutputMode},
167+
ospath::{OsPath, OsPathOrFd, OutputMode},
166168
protocol::PyIterReturn,
167169
recursion::ReprGuard,
168170
types::{IterNext, Iterable, PyStructSequence, Representable, SelfIter, Unconstructible},
@@ -1127,10 +1129,10 @@ pub(super) mod _os {
11271129
#[pyfunction(name = "replace")]
11281130
fn rename(src: OsPath, dst: OsPath, vm: &VirtualMachine) -> PyResult<()> {
11291131
fs::rename(&src.path, &dst.path).map_err(|err| {
1130-
OSErrorBuilder::new(&err)
1131-
.filename(src)
1132-
.filename2(dst)
1133-
.into_pyexception(vm)
1132+
let builder = err.to_os_error_builder(vm);
1133+
let builder = builder.filename(src.filename(vm));
1134+
let builder = builder.filename2(dst.filename(vm));
1135+
builder.build(vm).upcast()
11341136
})
11351137
}
11361138

@@ -1219,10 +1221,10 @@ pub(super) mod _os {
12191221
#[pyfunction]
12201222
fn link(src: OsPath, dst: OsPath, vm: &VirtualMachine) -> PyResult<()> {
12211223
fs::hard_link(&src.path, &dst.path).map_err(|err| {
1222-
OSErrorBuilder::new(&err)
1223-
.filename(src)
1224-
.filename2(dst)
1225-
.into_pyexception(vm)
1224+
let builder = err.to_os_error_builder(vm);
1225+
let builder = builder.filename(src.filename(vm));
1226+
let builder = builder.filename2(dst.filename(vm));
1227+
builder.build(vm).upcast()
12261228
})
12271229
}
12281230

crates/vm/src/stdlib/posix.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ pub mod module {
2626
AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
2727
builtins::{PyDictRef, PyInt, PyListRef, PyStrRef, PyTupleRef, PyType, PyUtf8StrRef},
2828
convert::{IntoPyException, ToPyObject, TryFromObject},
29+
exceptions::OSErrorBuilder,
2930
function::{Either, KwArgs, OptionalArg},
30-
ospath::{OSErrorBuilder, OsPath, OsPathOrFd},
31+
ospath::{OsPath, OsPathOrFd},
3132
stdlib::os::{_os, DirFd, FollowSymlinks, SupportFunc, TargetIsDirectory, fs_metadata},
3233
types::{Constructor, Representable},
3334
utils::ToCString,
@@ -482,7 +483,7 @@ pub mod module {
482483
#[cfg(not(target_os = "redox"))]
483484
#[pyfunction]
484485
fn chroot(path: OsPath, vm: &VirtualMachine) -> PyResult<()> {
485-
use crate::ospath::OSErrorBuilder;
486+
use crate::exceptions::OSErrorBuilder;
486487

487488
nix::unistd::chroot(&*path.path).map_err(|err| {
488489
// Use `From<nix::Error> for io::Error` when it is available

0 commit comments

Comments
 (0)