os: fix stat_result test

Implement tp_new for `stat_result`

To unpack args, this PR implement a `flatten_args` closure to
unpack args like
```
args = (1, 2, 3, 4, 5)
args = ((1, 2, 3, 4, 5))
args = (((1, 2, 3, 4, 5)))  # from pickle load
```
This commit is contained in:
Dean Li
2021-09-18 23:09:22 +08:00
parent a006aade5d
commit 96dcd68472
3 changed files with 50 additions and 5 deletions

4
Lib/test/test_os.py vendored
View File

@@ -443,13 +443,9 @@ class StatAttributeTests(unittest.TestCase):
except TypeError:
pass
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_stat_attributes(self):
self.check_stat_attributes(self.fname)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_stat_attributes_bytes(self):
try:
fname = self.fname.encode(sys.getfilesystemencoding())

View File

@@ -118,6 +118,12 @@ impl_try_from_object_int!(
(u64, to_u64),
);
impl TryFromBorrowedObject for BigInt {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Self> {
try_value_from_borrowed_object(vm, obj, |int: &PyInt| Ok(int.as_bigint().clone()))
}
}
// _PyLong_AsUnsignedLongMask
pub fn bigint_unsigned_mask(v: &BigInt) -> u32 {
v.to_u32()

View File

@@ -9,6 +9,7 @@ use std::{env, fs};
use crate::crt_fd::Fd;
use crossbeam_utils::atomic::AtomicCell;
use itertools::Itertools;
use num_bigint::BigInt;
#[cfg(unix)]
use strum_macros::EnumString;
@@ -1042,24 +1043,40 @@ mod _os {
#[pyattr]
#[pyclass(module = "os", name = "stat_result")]
#[derive(Debug, PyStructSequence)]
#[derive(Debug, PyStructSequence, FromArgs)]
struct StatResult {
#[pyarg(any)]
pub st_mode: BigInt,
#[pyarg(any)]
pub st_ino: BigInt,
#[pyarg(any)]
pub st_dev: BigInt,
#[pyarg(any)]
pub st_nlink: BigInt,
#[pyarg(any)]
pub st_uid: BigInt,
#[pyarg(any)]
pub st_gid: BigInt,
#[pyarg(any)]
pub st_size: BigInt,
// TODO: unnamed structsequence fields
#[pyarg(positional, default)]
pub __st_atime_int: BigInt,
#[pyarg(positional, default)]
pub __st_mtime_int: BigInt,
#[pyarg(positional, default)]
pub __st_ctime_int: BigInt,
#[pyarg(any, default)]
pub st_atime: f64,
#[pyarg(any, default)]
pub st_mtime: f64,
#[pyarg(any, default)]
pub st_ctime: f64,
#[pyarg(any, default)]
pub st_atime_ns: BigInt,
#[pyarg(any, default)]
pub st_mtime_ns: BigInt,
#[pyarg(any, default)]
pub st_ctime_ns: BigInt,
}
@@ -1102,6 +1119,32 @@ mod _os {
st_ctime_ns: to_ns(ctime).into(),
}
}
#[pyslot]
fn tp_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let flatten_args = |r: &[PyObjectRef]| {
let mut vec_args = Vec::from(r);
loop {
if let Ok(obj) = vec_args.iter().exactly_one() {
match obj.payload::<PyTuple>() {
Some(t) => {
vec_args = Vec::from(t.as_slice());
}
None => {
return vec_args;
}
}
} else {
return vec_args;
}
}
};
let args: FuncArgs = flatten_args(args.args.as_slice()).into();
let stat: StatResult = args.bind(vm)?;
Ok(stat.into_pyobject(vm))
}
}
#[cfg(not(windows))]