Skip to content

Commit 133aada

Browse files
authored
Update os.py from 3.13.5 (RustPython#6076)
* Update `os.py` from 3.13.5 * Set availablity of some `os` functions * revert some cfg * Mark more failing tests
1 parent 4ae5a1f commit 133aada

File tree

3 files changed

+827
-113
lines changed

3 files changed

+827
-113
lines changed

Lib/os.py

Lines changed: 97 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def _add(str, fn):
110110
_add("HAVE_FCHMODAT", "chmod")
111111
_add("HAVE_FCHOWNAT", "chown")
112112
_add("HAVE_FSTATAT", "stat")
113+
_add("HAVE_LSTAT", "lstat")
113114
_add("HAVE_FUTIMESAT", "utime")
114115
_add("HAVE_LINKAT", "link")
115116
_add("HAVE_MKDIRAT", "mkdir")
@@ -131,6 +132,7 @@ def _add(str, fn):
131132
_set = set()
132133
_add("HAVE_FCHDIR", "chdir")
133134
_add("HAVE_FCHMOD", "chmod")
135+
_add("MS_WINDOWS", "chmod")
134136
_add("HAVE_FCHOWN", "chown")
135137
_add("HAVE_FDOPENDIR", "listdir")
136138
_add("HAVE_FDOPENDIR", "scandir")
@@ -171,6 +173,7 @@ def _add(str, fn):
171173
_add("HAVE_FSTATAT", "stat")
172174
_add("HAVE_LCHFLAGS", "chflags")
173175
_add("HAVE_LCHMOD", "chmod")
176+
_add("MS_WINDOWS", "chmod")
174177
if _exists("lchown"): # mac os x10.3
175178
_add("HAVE_LCHOWN", "chown")
176179
_add("HAVE_LINKAT", "link")
@@ -279,6 +282,10 @@ def renames(old, new):
279282

280283
__all__.extend(["makedirs", "removedirs", "renames"])
281284

285+
# Private sentinel that makes walk() classify all symlinks and junctions as
286+
# regular files.
287+
_walk_symlinks_as_files = object()
288+
282289
def walk(top, topdown=True, onerror=None, followlinks=False):
283290
"""Directory tree generator.
284291
@@ -331,12 +338,12 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
331338
332339
import os
333340
from os.path import join, getsize
334-
for root, dirs, files in os.walk('python/Lib/email'):
341+
for root, dirs, files in os.walk('python/Lib/xml'):
335342
print(root, "consumes ")
336343
print(sum(getsize(join(root, name)) for name in files), end=" ")
337344
print("bytes in", len(files), "non-directory files")
338-
if 'CVS' in dirs:
339-
dirs.remove('CVS') # don't visit CVS directories
345+
if '__pycache__' in dirs:
346+
dirs.remove('__pycache__') # don't visit __pycache__ directories
340347
341348
"""
342349
sys.audit("os.walk", top, topdown, onerror, followlinks)
@@ -380,7 +387,10 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
380387
break
381388

382389
try:
383-
is_dir = entry.is_dir()
390+
if followlinks is _walk_symlinks_as_files:
391+
is_dir = entry.is_dir(follow_symlinks=False) and not entry.is_junction()
392+
else:
393+
is_dir = entry.is_dir()
384394
except OSError:
385395
# If is_dir() raises an OSError, consider the entry not to
386396
# be a directory, same behaviour as os.path.isdir().
@@ -459,34 +469,69 @@ def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=
459469
Example:
460470
461471
import os
462-
for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
472+
for root, dirs, files, rootfd in os.fwalk('python/Lib/xml'):
463473
print(root, "consumes", end="")
464474
print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
465475
end="")
466476
print("bytes in", len(files), "non-directory files")
467-
if 'CVS' in dirs:
468-
dirs.remove('CVS') # don't visit CVS directories
477+
if '__pycache__' in dirs:
478+
dirs.remove('__pycache__') # don't visit __pycache__ directories
469479
"""
470480
sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
471481
top = fspath(top)
472-
# Note: To guard against symlink races, we use the standard
473-
# lstat()/open()/fstat() trick.
474-
if not follow_symlinks:
475-
orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
476-
topfd = open(top, O_RDONLY | O_NONBLOCK, dir_fd=dir_fd)
482+
stack = [(_fwalk_walk, (True, dir_fd, top, top, None))]
483+
isbytes = isinstance(top, bytes)
477484
try:
478-
if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
479-
path.samestat(orig_st, stat(topfd)))):
480-
yield from _fwalk(topfd, top, isinstance(top, bytes),
481-
topdown, onerror, follow_symlinks)
485+
while stack:
486+
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
482487
finally:
483-
close(topfd)
484-
485-
def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
488+
# Close any file descriptors still on the stack.
489+
while stack:
490+
action, value = stack.pop()
491+
if action == _fwalk_close:
492+
close(value)
493+
494+
# Each item in the _fwalk() stack is a pair (action, args).
495+
_fwalk_walk = 0 # args: (isroot, dirfd, toppath, topname, entry)
496+
_fwalk_yield = 1 # args: (toppath, dirnames, filenames, topfd)
497+
_fwalk_close = 2 # args: dirfd
498+
499+
def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
486500
# Note: This uses O(depth of the directory tree) file descriptors: if
487501
# necessary, it can be adapted to only require O(1) FDs, see issue
488502
# #13734.
489503

504+
action, value = stack.pop()
505+
if action == _fwalk_close:
506+
close(value)
507+
return
508+
elif action == _fwalk_yield:
509+
yield value
510+
return
511+
assert action == _fwalk_walk
512+
isroot, dirfd, toppath, topname, entry = value
513+
try:
514+
if not follow_symlinks:
515+
# Note: To guard against symlink races, we use the standard
516+
# lstat()/open()/fstat() trick.
517+
if entry is None:
518+
orig_st = stat(topname, follow_symlinks=False, dir_fd=dirfd)
519+
else:
520+
orig_st = entry.stat(follow_symlinks=False)
521+
topfd = open(topname, O_RDONLY | O_NONBLOCK, dir_fd=dirfd)
522+
except OSError as err:
523+
if isroot:
524+
raise
525+
if onerror is not None:
526+
onerror(err)
527+
return
528+
stack.append((_fwalk_close, topfd))
529+
if not follow_symlinks:
530+
if isroot and not st.S_ISDIR(orig_st.st_mode):
531+
return
532+
if not path.samestat(orig_st, stat(topfd)):
533+
return
534+
490535
scandir_it = scandir(topfd)
491536
dirs = []
492537
nondirs = []
@@ -512,31 +557,18 @@ def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
512557

513558
if topdown:
514559
yield toppath, dirs, nondirs, topfd
560+
else:
561+
stack.append((_fwalk_yield, (toppath, dirs, nondirs, topfd)))
515562

516-
for name in dirs if entries is None else zip(dirs, entries):
517-
try:
518-
if not follow_symlinks:
519-
if topdown:
520-
orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
521-
else:
522-
assert entries is not None
523-
name, entry = name
524-
orig_st = entry.stat(follow_symlinks=False)
525-
dirfd = open(name, O_RDONLY | O_NONBLOCK, dir_fd=topfd)
526-
except OSError as err:
527-
if onerror is not None:
528-
onerror(err)
529-
continue
530-
try:
531-
if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
532-
dirpath = path.join(toppath, name)
533-
yield from _fwalk(dirfd, dirpath, isbytes,
534-
topdown, onerror, follow_symlinks)
535-
finally:
536-
close(dirfd)
537-
538-
if not topdown:
539-
yield toppath, dirs, nondirs, topfd
563+
toppath = path.join(toppath, toppath[:0]) # Add trailing slash.
564+
if entries is None:
565+
stack.extend(
566+
(_fwalk_walk, (False, topfd, toppath + name, name, None))
567+
for name in dirs[::-1])
568+
else:
569+
stack.extend(
570+
(_fwalk_walk, (False, topfd, toppath + name, name, entry))
571+
for name, entry in zip(dirs[::-1], entries[::-1]))
540572

541573
__all__.append("fwalk")
542574

@@ -1061,6 +1093,12 @@ def _fspath(path):
10611093
else:
10621094
raise TypeError("expected str, bytes or os.PathLike object, "
10631095
"not " + path_type.__name__)
1096+
except TypeError:
1097+
if path_type.__fspath__ is None:
1098+
raise TypeError("expected str, bytes or os.PathLike object, "
1099+
"not " + path_type.__name__) from None
1100+
else:
1101+
raise
10641102
if isinstance(path_repr, (str, bytes)):
10651103
return path_repr
10661104
else:
@@ -1079,6 +1117,8 @@ class PathLike(abc.ABC):
10791117

10801118
"""Abstract base class for implementing the file system path protocol."""
10811119

1120+
__slots__ = ()
1121+
10821122
@abc.abstractmethod
10831123
def __fspath__(self):
10841124
"""Return the file system path representation of the object."""
@@ -1128,3 +1168,17 @@ def add_dll_directory(path):
11281168
cookie,
11291169
nt._remove_dll_directory
11301170
)
1171+
1172+
1173+
if _exists('sched_getaffinity') and sys._get_cpu_count_config() < 0:
1174+
def process_cpu_count():
1175+
"""
1176+
Get the number of CPUs of the current process.
1177+
1178+
Return the number of logical CPUs usable by the calling thread of the
1179+
current process. Return None if indeterminable.
1180+
"""
1181+
return len(sched_getaffinity(0))
1182+
else:
1183+
# Just an alias to cpu_count() (same docstring)
1184+
process_cpu_count = cpu_count

0 commit comments

Comments
 (0)