Skip to content

Commit b01d756

Browse files
authored
Merge pull request #964 from youknowone/os-supports-placeholders
Add os.supports_* placeholders
2 parents 95a894a + 64afd5c commit b01d756

File tree

3 files changed

+164
-28
lines changed

3 files changed

+164
-28
lines changed

tests/snippets/stdlib_os.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
217217
os.chdir(tmpdir)
218218
assert os.getcwd() == tmpdir
219219
os.path.exists(FILE_NAME)
220+
221+
# supports
222+
assert isinstance(os.supports_fd, set)
223+
assert isinstance(os.supports_dir_fd, set)
224+
assert isinstance(os.supports_follow_symlinks, set)

vm/src/obj/objset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ impl PySetRef {
472472
Ok(vm.new_str(s))
473473
}
474474

475-
fn add(self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult {
475+
pub fn add(self, item: PyObjectRef, vm: &VirtualMachine) -> PyResult {
476476
self.inner.borrow_mut().add(&item, vm)
477477
}
478478

vm/src/stdlib/os.rs

Lines changed: 158 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ use std::{env, fs};
77

88
use num_traits::cast::ToPrimitive;
99

10-
use crate::function::PyFuncArgs;
10+
use crate::function::{IntoPyNativeFunc, PyFuncArgs};
1111
use crate::obj::objbytes::PyBytesRef;
1212
use crate::obj::objdict::PyDictRef;
13-
use crate::obj::objint;
14-
use crate::obj::objint::PyIntRef;
13+
use crate::obj::objint::{self, PyInt, PyIntRef};
1514
use crate::obj::objiter;
16-
use crate::obj::objstr;
17-
use crate::obj::objstr::PyStringRef;
15+
use crate::obj::objset::PySet;
16+
use crate::obj::objstr::{self, PyString, PyStringRef};
1817
use crate::obj::objtype::PyClassRef;
1918
use crate::pyobject::{
2019
ItemProtocol, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, TryIntoRef,
@@ -61,6 +60,14 @@ pub fn raw_file_number(handle: File) -> i64 {
6160
unimplemented!();
6261
}
6362

63+
fn make_path(_vm: &VirtualMachine, path: PyStringRef, dir_fd: &DirFd) -> PyStringRef {
64+
if dir_fd.dir_fd.is_some() {
65+
unimplemented!();
66+
} else {
67+
path
68+
}
69+
}
70+
6471
pub fn os_close(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
6572
arg_check!(vm, args, required = [(fileno, Some(vm.ctx.int_type()))]);
6673

@@ -81,10 +88,19 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
8188
required = [
8289
(name, Some(vm.ctx.str_type())),
8390
(mode, Some(vm.ctx.int_type()))
84-
]
91+
],
92+
optional = [(dir_fd, Some(vm.ctx.int_type()))]
8593
);
8694

87-
let fname = objstr::get_value(&name);
95+
let name = name.clone().downcast::<PyString>().unwrap();
96+
let dir_fd = if let Some(obj) = dir_fd {
97+
DirFd {
98+
dir_fd: Some(obj.clone().downcast::<PyInt>().unwrap()),
99+
}
100+
} else {
101+
DirFd::default()
102+
};
103+
let fname = &make_path(vm, name, &dir_fd).value;
88104

89105
let handle = match objint::get_value(mode).to_u16().unwrap() {
90106
0 => OpenOptions::new().read(true).open(&fname),
@@ -159,19 +175,22 @@ fn os_write(fd: PyIntRef, data: PyBytesRef, vm: &VirtualMachine) -> PyResult {
159175
Ok(vm.ctx.new_int(written))
160176
}
161177

162-
fn os_remove(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
178+
fn os_remove(path: PyStringRef, dir_fd: DirFd, vm: &VirtualMachine) -> PyResult<()> {
179+
let path = make_path(vm, path, &dir_fd);
163180
fs::remove_file(&path.value).map_err(|s| vm.new_os_error(s.to_string()))
164181
}
165182

166-
fn os_mkdir(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
183+
fn os_mkdir(path: PyStringRef, dir_fd: DirFd, vm: &VirtualMachine) -> PyResult<()> {
184+
let path = make_path(vm, path, &dir_fd);
167185
fs::create_dir(&path.value).map_err(|s| vm.new_os_error(s.to_string()))
168186
}
169187

170188
fn os_mkdirs(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
171189
fs::create_dir_all(&path.value).map_err(|s| vm.new_os_error(s.to_string()))
172190
}
173191

174-
fn os_rmdir(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
192+
fn os_rmdir(path: PyStringRef, dir_fd: DirFd, vm: &VirtualMachine) -> PyResult<()> {
193+
let path = make_path(vm, path, &dir_fd);
175194
fs::remove_dir(&path.value).map_err(|s| vm.new_os_error(s.to_string()))
176195
}
177196

@@ -219,6 +238,12 @@ impl PyValue for DirEntry {
219238
}
220239
}
221240

241+
#[derive(FromArgs, Default)]
242+
struct DirFd {
243+
#[pyarg(keyword_only, default = "None")]
244+
dir_fd: Option<PyIntRef>,
245+
}
246+
222247
#[derive(FromArgs)]
223248
struct FollowSymlinks {
224249
#[pyarg(keyword_only, default = "true")]
@@ -272,8 +297,13 @@ impl DirEntryRef {
272297
.is_symlink())
273298
}
274299

275-
fn stat(self, follow_symlinks: FollowSymlinks, vm: &VirtualMachine) -> PyResult<StatResult> {
276-
os_stat(self.path(vm).try_into_ref(vm)?, follow_symlinks, vm)
300+
fn stat(
301+
self,
302+
dir_fd: DirFd,
303+
follow_symlinks: FollowSymlinks,
304+
vm: &VirtualMachine,
305+
) -> PyResult<StatResult> {
306+
os_stat(self.path(vm).try_into_ref(vm)?, dir_fd, follow_symlinks, vm)
277307
}
278308
}
279309

@@ -432,30 +462,36 @@ macro_rules! os_unix_stat_inner {
432462
#[cfg(target_os = "linux")]
433463
fn os_stat(
434464
path: PyStringRef,
465+
dir_fd: DirFd,
435466
follow_symlinks: FollowSymlinks,
436467
vm: &VirtualMachine,
437468
) -> PyResult<StatResult> {
438469
use std::os::linux::fs::MetadataExt;
470+
let path = make_path(vm, path, &dir_fd);
439471
os_unix_stat_inner!(path, follow_symlinks, vm)
440472
}
441473

442474
#[cfg(target_os = "macos")]
443475
fn os_stat(
444476
path: PyStringRef,
477+
dir_fd: DirFd,
445478
follow_symlinks: FollowSymlinks,
446479
vm: &VirtualMachine,
447480
) -> PyResult<StatResult> {
448481
use std::os::macos::fs::MetadataExt;
482+
let path = make_path(vm, path, &dir_fd);
449483
os_unix_stat_inner!(path, follow_symlinks, vm)
450484
}
451485

452486
#[cfg(target_os = "android")]
453487
fn os_stat(
454488
path: PyStringRef,
489+
dir_fd: DirFd,
455490
follow_symlinks: FollowSymlinks,
456491
vm: &VirtualMachine,
457492
) -> PyResult<StatResult> {
458493
use std::os::android::fs::MetadataExt;
494+
let path = make_path(vm, path, &dir_fd);
459495
os_unix_stat_inner!(path, follow_symlinks, vm)
460496
}
461497

@@ -483,6 +519,7 @@ fn attributes_to_mode(attr: u32) -> u32 {
483519
#[cfg(windows)]
484520
fn os_stat(
485521
path: PyStringRef,
522+
_dir_fd: DirFd, // TODO: error
486523
follow_symlinks: FollowSymlinks,
487524
vm: &VirtualMachine,
488525
) -> PyResult<StatResult> {
@@ -523,13 +560,24 @@ fn os_stat(path: PyStringRef, vm: &VirtualMachine) -> PyResult {
523560
}
524561

525562
#[cfg(unix)]
526-
fn os_symlink(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
563+
fn os_symlink(
564+
src: PyStringRef,
565+
dst: PyStringRef,
566+
dir_fd: DirFd,
567+
vm: &VirtualMachine,
568+
) -> PyResult<()> {
527569
use std::os::unix::fs as unix_fs;
570+
let dst = make_path(vm, dst, &dir_fd);
528571
unix_fs::symlink(&src.value, &dst.value).map_err(|s| vm.new_os_error(s.to_string()))
529572
}
530573

531574
#[cfg(windows)]
532-
fn os_symlink(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
575+
fn os_symlink(
576+
src: PyStringRef,
577+
dst: PyStringRef,
578+
_dir_fd: DirFd,
579+
vm: &VirtualMachine,
580+
) -> PyResult<()> {
533581
use std::os::windows::fs as win_fs;
534582
let ret = match fs::metadata(&dst.value) {
535583
Ok(meta) => {
@@ -547,7 +595,12 @@ fn os_symlink(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResu
547595
}
548596

549597
#[cfg(all(not(unix), not(windows)))]
550-
fn os_symlink(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
598+
fn os_symlink(
599+
src: PyStringRef,
600+
dst: PyStringRef,
601+
dir_fd: DirFd,
602+
vm: &VirtualMachine,
603+
) -> PyResult<()> {
551604
unimplemented!();
552605
}
553606

@@ -600,36 +653,114 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
600653
"st_mtime" => ctx.new_property(StatResultRef::st_mtime),
601654
});
602655

603-
py_module!(vm, "_os", {
604-
"open" => ctx.new_rustfunc(os_open),
656+
struct SupportFunc<'a> {
657+
name: &'a str,
658+
func_obj: PyObjectRef,
659+
fd: Option<bool>,
660+
dir_fd: Option<bool>,
661+
follow_symlinks: Option<bool>,
662+
};
663+
impl<'a> SupportFunc<'a> {
664+
fn new<F, T, R>(
665+
vm: &VirtualMachine,
666+
name: &'a str,
667+
func: F,
668+
fd: Option<bool>,
669+
dir_fd: Option<bool>,
670+
follow_symlinks: Option<bool>,
671+
) -> Self
672+
where
673+
F: IntoPyNativeFunc<T, R>,
674+
{
675+
Self {
676+
name: name,
677+
func_obj: vm.ctx.new_rustfunc(func),
678+
fd: fd,
679+
dir_fd: dir_fd,
680+
follow_symlinks: follow_symlinks,
681+
}
682+
}
683+
}
684+
let support_funcs = vec![
685+
SupportFunc::new(vm, "open", os_open, None, Some(false), None),
686+
// access Some Some None
687+
SupportFunc::new(vm, "chdir", os_chdir, Some(false), None, None),
688+
// chflags Some, None Some
689+
// chmod Some Some Some
690+
// chown Some Some Some
691+
// chroot Some None None
692+
SupportFunc::new(vm, "listdir", os_listdir, Some(false), None, None),
693+
SupportFunc::new(vm, "mkdir", os_mkdir, Some(false), Some(false), None),
694+
// mkfifo Some Some None
695+
// mknod Some Some None
696+
// pathconf Some None None
697+
// readlink Some Some None
698+
SupportFunc::new(vm, "remove", os_remove, Some(false), Some(false), None),
699+
// rename Some Some None
700+
// replace Some Some None
701+
SupportFunc::new(vm, "rmdir", os_rmdir, Some(false), Some(false), None),
702+
SupportFunc::new(vm, "scandir", os_scandir, Some(false), None, None),
703+
SupportFunc::new(vm, "stat", os_stat, Some(false), Some(false), Some(false)),
704+
SupportFunc::new(vm, "symlink", os_symlink, None, Some(false), None),
705+
// truncate Some None None
706+
SupportFunc::new(vm, "unlink", os_remove, Some(false), Some(false), None),
707+
// utime Some Some Some
708+
];
709+
let supports_fd = PySet::default().into_ref(vm);
710+
let supports_dir_fd = PySet::default().into_ref(vm);
711+
let supports_follow_symlinks = PySet::default().into_ref(vm);
712+
713+
let module = py_module!(vm, "_os", {
605714
"close" => ctx.new_rustfunc(os_close),
606715
"error" => ctx.new_rustfunc(os_error),
607716
"fsync" => ctx.new_rustfunc(os_fsync),
608717
"read" => ctx.new_rustfunc(os_read),
609718
"write" => ctx.new_rustfunc(os_write),
610-
"remove" => ctx.new_rustfunc(os_remove),
611-
"unlink" => ctx.new_rustfunc(os_remove),
612-
"mkdir" => ctx.new_rustfunc(os_mkdir),
613719
"mkdirs" => ctx.new_rustfunc(os_mkdirs),
614-
"rmdir" => ctx.new_rustfunc(os_rmdir),
615-
"listdir" => ctx.new_rustfunc(os_listdir),
616720
"putenv" => ctx.new_rustfunc(os_putenv),
617721
"unsetenv" => ctx.new_rustfunc(os_unsetenv),
618722
"environ" => environ,
619723
"name" => ctx.new_str(os_name),
620-
"scandir" => ctx.new_rustfunc(os_scandir),
621724
"ScandirIter" => scandir_iter,
622725
"DirEntry" => dir_entry,
623726
"stat_result" => stat_result,
624-
"stat" => ctx.new_rustfunc(os_stat),
625-
"symlink" => ctx.new_rustfunc(os_symlink),
626727
"getcwd" => ctx.new_rustfunc(os_getcwd),
627-
"chdir" => ctx.new_rustfunc(os_chdir),
628728
"O_RDONLY" => ctx.new_int(0),
629729
"O_WRONLY" => ctx.new_int(1),
630730
"O_RDWR" => ctx.new_int(2),
631731
"O_NONBLOCK" => ctx.new_int(4),
632732
"O_APPEND" => ctx.new_int(8),
633733
"O_CREAT" => ctx.new_int(512)
634-
})
734+
});
735+
736+
for support in support_funcs {
737+
if support.fd.unwrap_or(false) {
738+
supports_fd
739+
.clone()
740+
.add(support.func_obj.clone(), vm)
741+
.unwrap();
742+
}
743+
if support.dir_fd.unwrap_or(false) {
744+
supports_dir_fd
745+
.clone()
746+
.add(support.func_obj.clone(), vm)
747+
.unwrap();
748+
}
749+
if support.follow_symlinks.unwrap_or(false) {
750+
supports_follow_symlinks
751+
.clone()
752+
.add(support.func_obj.clone(), vm)
753+
.unwrap();
754+
}
755+
vm.set_attr(&module, support.name, support.func_obj)
756+
.unwrap();
757+
}
758+
759+
extend_module!(vm, module, {
760+
"supports_fd" => supports_fd.into_object(),
761+
"supports_dir_fd" => supports_dir_fd.into_object(),
762+
"supports_follow_symlinks" => supports_follow_symlinks.into_object(),
763+
});
764+
765+
module
635766
}

0 commit comments

Comments
 (0)