Update os.py from 3.13.5 (#6076)

* Update `os.py` from 3.13.5

* Set availablity of some `os` functions

* revert some cfg

* Mark more failing tests
This commit is contained in:
Shahar Naveh authored and GitHub committed 2025-08-08 14:37:35 +09:00
1 parent 4ae5a1f894
commit 133aada0b7
3 files changed
+827 -113

No files matched your search

Vendored
+96 -42
View File
@@ -110,6 +110,7 @@ if _exists("_have_functions"):
_add("HAVE_FCHMODAT", "chmod")
_add("HAVE_FCHOWNAT", "chown")
_add("HAVE_FSTATAT", "stat")
_add("HAVE_LSTAT", "lstat")
_add("HAVE_FUTIMESAT", "utime")
_add("HAVE_LINKAT", "link")
_add("HAVE_MKDIRAT", "mkdir")
@@ -131,6 +132,7 @@ if _exists("_have_functions"):
_set = set()
_add("HAVE_FCHDIR", "chdir")
_add("HAVE_FCHMOD", "chmod")
_add("MS_WINDOWS", "chmod")
_add("HAVE_FCHOWN", "chown")
_add("HAVE_FDOPENDIR", "listdir")
_add("HAVE_FDOPENDIR", "scandir")
@@ -171,6 +173,7 @@ if _exists("_have_functions"):
_add("HAVE_FSTATAT", "stat")
_add("HAVE_LCHFLAGS", "chflags")
_add("HAVE_LCHMOD", "chmod")
_add("MS_WINDOWS", "chmod")
if _exists("lchown"): # mac os x10.3
_add("HAVE_LCHOWN", "chown")
_add("HAVE_LINKAT", "link")
@@ -279,6 +282,10 @@ def renames(old, new):
__all__.extend(["makedirs", "removedirs", "renames"])
# Private sentinel that makes walk() classify all symlinks and junctions as
# regular files.
_walk_symlinks_as_files = object()
def walk(top, topdown=True, onerror=None, followlinks=False):
"""Directory tree generator.
@@ -331,12 +338,12 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
import os
from os.path import join, getsize
for root, dirs, files in os.walk('python/Lib/email'):
for root, dirs, files in os.walk('python/Lib/xml'):
print(root, "consumes ")
print(sum(getsize(join(root, name)) for name in files), end=" ")
print("bytes in", len(files), "non-directory files")
if 'CVS' in dirs:
dirs.remove('CVS') # don't visit CVS directories
if '__pycache__' in dirs:
dirs.remove('__pycache__') # don't visit __pycache__ directories
"""
sys.audit("os.walk", top, topdown, onerror, followlinks)
@@ -380,7 +387,10 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
break
try:
is_dir = entry.is_dir()
if followlinks is _walk_symlinks_as_files:
is_dir = entry.is_dir(follow_symlinks=False) and not entry.is_junction()
else:
is_dir = entry.is_dir()
except OSError:
# If is_dir() raises an OSError, consider the entry not to
# be a directory, same behaviour as os.path.isdir().
@@ -459,34 +469,69 @@ if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
Example:
import os
for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
for root, dirs, files, rootfd in os.fwalk('python/Lib/xml'):
print(root, "consumes", end="")
print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
end="")
print("bytes in", len(files), "non-directory files")
if 'CVS' in dirs:
dirs.remove('CVS') # don't visit CVS directories
if '__pycache__' in dirs:
dirs.remove('__pycache__') # don't visit __pycache__ directories
"""
sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
top = fspath(top)
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
if not follow_symlinks:
orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
topfd = open(top, O_RDONLY | O_NONBLOCK, dir_fd=dir_fd)
stack = [(_fwalk_walk, (True, dir_fd, top, top, None))]
isbytes = isinstance(top, bytes)
try:
if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
path.samestat(orig_st, stat(topfd)))):
yield from _fwalk(topfd, top, isinstance(top, bytes),
topdown, onerror, follow_symlinks)
while stack:
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
finally:
close(topfd)
# Close any file descriptors still on the stack.
while stack:
action, value = stack.pop()
if action == _fwalk_close:
close(value)
def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
# Each item in the _fwalk() stack is a pair (action, args).
_fwalk_walk = 0 # args: (isroot, dirfd, toppath, topname, entry)
_fwalk_yield = 1 # args: (toppath, dirnames, filenames, topfd)
_fwalk_close = 2 # args: dirfd
def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
# Note: This uses O(depth of the directory tree) file descriptors: if
# necessary, it can be adapted to only require O(1) FDs, see issue
# #13734.
action, value = stack.pop()
if action == _fwalk_close:
close(value)
return
elif action == _fwalk_yield:
yield value
return
assert action == _fwalk_walk
isroot, dirfd, toppath, topname, entry = value
try:
if not follow_symlinks:
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
if entry is None:
orig_st = stat(topname, follow_symlinks=False, dir_fd=dirfd)
else:
orig_st = entry.stat(follow_symlinks=False)
topfd = open(topname, O_RDONLY | O_NONBLOCK, dir_fd=dirfd)
except OSError as err:
if isroot:
raise
if onerror is not None:
onerror(err)
return
stack.append((_fwalk_close, topfd))
if not follow_symlinks:
if isroot and not st.S_ISDIR(orig_st.st_mode):
return
if not path.samestat(orig_st, stat(topfd)):
return
scandir_it = scandir(topfd)
dirs = []
nondirs = []
@@ -512,31 +557,18 @@ if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
if topdown:
yield toppath, dirs, nondirs, topfd
else:
stack.append((_fwalk_yield, (toppath, dirs, nondirs, topfd)))
for name in dirs if entries is None else zip(dirs, entries):
try:
if not follow_symlinks:
if topdown:
orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
else:
assert entries is not None
name, entry = name
orig_st = entry.stat(follow_symlinks=False)
dirfd = open(name, O_RDONLY | O_NONBLOCK, dir_fd=topfd)
except OSError as err:
if onerror is not None:
onerror(err)
continue
try:
if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
dirpath = path.join(toppath, name)
yield from _fwalk(dirfd, dirpath, isbytes,
topdown, onerror, follow_symlinks)
finally:
close(dirfd)
if not topdown:
yield toppath, dirs, nondirs, topfd
toppath = path.join(toppath, toppath[:0]) # Add trailing slash.
if entries is None:
stack.extend(
(_fwalk_walk, (False, topfd, toppath + name, name, None))
for name in dirs[::-1])
else:
stack.extend(
(_fwalk_walk, (False, topfd, toppath + name, name, entry))
for name, entry in zip(dirs[::-1], entries[::-1]))
__all__.append("fwalk")
@@ -1061,6 +1093,12 @@ def _fspath(path):
else:
raise TypeError("expected str, bytes or os.PathLike object, "
"not " + path_type.__name__)
except TypeError:
if path_type.__fspath__ is None:
raise TypeError("expected str, bytes or os.PathLike object, "
"not " + path_type.__name__) from None
else:
raise
if isinstance(path_repr, (str, bytes)):
return path_repr
else:
@@ -1079,6 +1117,8 @@ class PathLike(abc.ABC):
"""Abstract base class for implementing the file system path protocol."""
__slots__ = ()
@abc.abstractmethod
def __fspath__(self):
"""Return the file system path representation of the object."""
@@ -1128,3 +1168,17 @@ if name == 'nt':
cookie,
nt._remove_dll_directory
)
if _exists('sched_getaffinity') and sys._get_cpu_count_config() < 0:
def process_cpu_count():
"""
Get the number of CPUs of the current process.
Return the number of logical CPUs usable by the calling thread of the
current process. Return None if indeterminable.
"""
return len(sched_getaffinity(0))
else:
# Just an alias to cpu_count() (same docstring)
process_cpu_count = cpu_count
+681 -57
View File
File diff suppressed because it is too large. Load diff
+50 -14
View File
@@ -62,11 +62,14 @@ pub mod module {
#[cfg(not(any(target_os = "redox", target_os = "freebsd")))]
#[pyattr]
use libc::O_DSYNC;
#[pyattr]
use libc::{O_CLOEXEC, O_NONBLOCK, WNOHANG};
#[cfg(target_os = "macos")]
#[pyattr]
use libc::{O_EVTONLY, O_FSYNC, O_NOFOLLOW_ANY, O_SYMLINK};
#[cfg(not(target_os = "redox"))]
#[pyattr]
use libc::{O_NDELAY, O_NOCTTY};
@@ -80,34 +83,49 @@ pub mod module {
#[pyattr]
const EX_OK: i8 = exitcode::OK as i8;
#[pyattr]
const EX_USAGE: i8 = exitcode::USAGE as i8;
#[pyattr]
const EX_DATAERR: i8 = exitcode::DATAERR as i8;
#[pyattr]
const EX_NOINPUT: i8 = exitcode::NOINPUT as i8;
#[pyattr]
const EX_NOUSER: i8 = exitcode::NOUSER as i8;
#[pyattr]
const EX_NOHOST: i8 = exitcode::NOHOST as i8;
#[pyattr]
const EX_UNAVAILABLE: i8 = exitcode::UNAVAILABLE as i8;
#[pyattr]
const EX_SOFTWARE: i8 = exitcode::SOFTWARE as i8;
#[pyattr]
const EX_OSERR: i8 = exitcode::OSERR as i8;
#[pyattr]
const EX_OSFILE: i8 = exitcode::OSFILE as i8;
#[pyattr]
const EX_CANTCREAT: i8 = exitcode::CANTCREAT as i8;
#[pyattr]
const EX_IOERR: i8 = exitcode::IOERR as i8;
#[pyattr]
const EX_TEMPFAIL: i8 = exitcode::TEMPFAIL as i8;
#[pyattr]
const EX_PROTOCOL: i8 = exitcode::PROTOCOL as i8;
#[pyattr]
const EX_NOPERM: i8 = exitcode::NOPERM as i8;
#[pyattr]
const EX_CONFIG: i8 = exitcode::CONFIG as i8;
@@ -122,6 +140,7 @@ pub mod module {
))]
#[pyattr]
const SCHED_RR: i32 = libc::SCHED_RR;
#[cfg(any(
target_os = "macos",
target_os = "linux",
@@ -133,6 +152,7 @@ pub mod module {
))]
#[pyattr]
const SCHED_FIFO: i32 = libc::SCHED_FIFO;
#[cfg(any(
target_os = "macos",
target_os = "linux",
@@ -143,9 +163,11 @@ pub mod module {
))]
#[pyattr]
const SCHED_OTHER: i32 = libc::SCHED_OTHER;
#[cfg(any(target_os = "linux", target_os = "android"))]
#[pyattr]
const SCHED_IDLE: i32 = libc::SCHED_IDLE;
#[cfg(any(target_os = "linux", target_os = "android"))]
#[pyattr]
const SCHED_BATCH: i32 = libc::SCHED_BATCH;
@@ -153,9 +175,11 @@ pub mod module {
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
#[pyattr]
const POSIX_SPAWN_OPEN: i32 = PosixSpawnFileActionIdentifier::Open as i32;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
#[pyattr]
const POSIX_SPAWN_CLOSE: i32 = PosixSpawnFileActionIdentifier::Close as i32;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
#[pyattr]
const POSIX_SPAWN_DUP2: i32 = PosixSpawnFileActionIdentifier::Dup2 as i32;
@@ -1099,12 +1123,13 @@ pub mod module {
vm.ctx.new_int(euid).into()
}
#[cfg(not(any(target_os = "wasi", target_os = "android")))]
#[pyfunction]
fn setgid(gid: Gid, vm: &VirtualMachine) -> PyResult<()> {
unistd::setgid(gid).map_err(|err| err.into_pyexception(vm))
}
#[cfg(not(target_os = "redox"))]
#[cfg(not(any(target_os = "wasi", target_os = "android", target_os = "redox")))]
#[pyfunction]
fn setegid(egid: Gid, vm: &VirtualMachine) -> PyResult<()> {
unistd::setegid(egid).map_err(|err| err.into_pyexception(vm))
@@ -1116,7 +1141,7 @@ pub mod module {
.map_err(|err| err.into_pyexception(vm))
}
#[cfg(not(target_os = "redox"))]
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
#[pyfunction]
fn setsid(vm: &VirtualMachine) -> PyResult<()> {
unistd::setsid()
@@ -1162,18 +1187,19 @@ pub mod module {
}
}
#[cfg(not(any(target_os = "wasi", target_os = "android")))]
#[pyfunction]
fn setuid(uid: Uid) -> nix::Result<()> {
unistd::setuid(uid)
}
#[cfg(not(target_os = "redox"))]
#[cfg(not(any(target_os = "wasi", target_os = "android", target_os = "redox")))]
#[pyfunction]
fn seteuid(euid: Uid) -> nix::Result<()> {
unistd::seteuid(euid)
}
#[cfg(not(target_os = "redox"))]
#[cfg(not(any(target_os = "wasi", target_os = "android", target_os = "redox")))]
#[pyfunction]
fn setreuid(ruid: Uid, euid: Uid) -> nix::Result<()> {
let ret = unsafe { libc::setreuid(ruid.as_raw(), euid.as_raw()) };
@@ -1271,7 +1297,7 @@ pub mod module {
unistd::setresgid(rgid, egid, sgid).map_err(|err| err.into_pyexception(vm))
}
#[cfg(not(target_os = "redox"))]
#[cfg(not(any(target_os = "wasi", target_os = "android", target_os = "redox")))]
#[pyfunction]
fn setregid(rgid: Gid, egid: Gid) -> nix::Result<()> {
let ret = unsafe { libc::setregid(rgid.as_raw(), egid.as_raw()) };
@@ -1602,9 +1628,14 @@ pub mod module {
args.spawn(true, vm)
}
#[pyfunction(name = "WIFSIGNALED")]
fn wifsignaled(status: i32) -> bool {
libc::WIFSIGNALED(status)
#[pyfunction(name = "WCOREDUMP")]
fn wcoredump(status: i32) -> bool {
libc::WCOREDUMP(status)
}
#[pyfunction(name = "WIFCONTINUED")]
fn wifcontinued(status: i32) -> bool {
libc::WIFCONTINUED(status)
}
#[pyfunction(name = "WIFSTOPPED")]
@@ -1612,14 +1643,19 @@ pub mod module {
libc::WIFSTOPPED(status)
}
#[pyfunction(name = "WIFSIGNALED")]
fn wifsignaled(status: i32) -> bool {
libc::WIFSIGNALED(status)
}
#[pyfunction(name = "WIFEXITED")]
fn wifexited(status: i32) -> bool {
libc::WIFEXITED(status)
}
#[pyfunction(name = "WTERMSIG")]
fn wtermsig(status: i32) -> i32 {
libc::WTERMSIG(status)
#[pyfunction(name = "WEXITSTATUS")]
fn wexitstatus(status: i32) -> i32 {
libc::WEXITSTATUS(status)
}
#[pyfunction(name = "WSTOPSIG")]
@@ -1627,9 +1663,9 @@ pub mod module {
libc::WSTOPSIG(status)
}
#[pyfunction(name = "WEXITSTATUS")]
fn wexitstatus(status: i32) -> i32 {
libc::WEXITSTATUS(status)
#[pyfunction(name = "WTERMSIG")]
fn wtermsig(status: i32) -> i32 {
libc::WTERMSIG(status)
}
#[pyfunction]