Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions Lib/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ def _get_exports_list(module):
__all__.append('_exit')
except ImportError:
pass
try:
from posix import _clearenv
__all__.append('_clearenv')
except ImportError:
pass
import posixpath as path

try:
Expand Down Expand Up @@ -131,6 +136,8 @@ def _add(str, fn):
_add("HAVE_UNLINKAT", "unlink")
_add("HAVE_UNLINKAT", "rmdir")
_add("HAVE_UTIMENSAT", "utime")
if _exists("statx"):
_set.add(statx)
supports_dir_fd = _set

_set = set()
Expand All @@ -152,6 +159,8 @@ def _add(str, fn):
_add("HAVE_FPATHCONF", "pathconf")
if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3
_add("HAVE_FSTATVFS", "statvfs")
if _exists("statx"):
_set.add(statx)
supports_fd = _set

_set = set()
Expand Down Expand Up @@ -190,6 +199,8 @@ def _add(str, fn):
_add("HAVE_FSTATAT", "stat")
_add("HAVE_UTIMENSAT", "utime")
_add("MS_WINDOWS", "stat")
if _exists("statx"):
_set.add(statx)
supports_follow_symlinks = _set

del _set
Expand All @@ -208,22 +219,29 @@ def _add(str, fn):
# Super directory utilities.
# (Inspired by Eric Raymond; the doc strings are mostly his)

def makedirs(name, mode=0o777, exist_ok=False):
"""makedirs(name [, mode=0o777][, exist_ok=False])
def makedirs(name, mode=0o777, exist_ok=False, *, parent_mode=None):
"""makedirs(name [, mode=0o777][, exist_ok=False][, parent_mode=None])

Super-mkdir; create a leaf directory and all intermediate ones. Works
like mkdir, except that any intermediate path segment (not just the
rightmost) will be created if it does not exist. If the target
directory already exists, raise an OSError if exist_ok is False.
Otherwise no exception is raised. This is recursive.
Otherwise no exception is raised. If parent_mode is not None, it will
be used as the mode for any newly-created, intermediate-level
directories. Otherwise, intermediate directories are created with the
default permissions (respecting umask). This is recursive.

"""
head, tail = path.split(name)
if not tail:
head, tail = path.split(head)
if head and tail and not path.exists(head):
try:
makedirs(head, exist_ok=exist_ok)
if parent_mode is not None:
makedirs(head, mode=parent_mode, exist_ok=exist_ok,
parent_mode=parent_mode)
else:
makedirs(head, exist_ok=exist_ok)
except FileExistsError:
# Defeats race condition when another thread created the path
pass
Expand Down Expand Up @@ -417,14 +435,16 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
# Yield before sub-directory traversal if going top down
yield top, dirs, nondirs
# Traverse into sub-directories
for dirname in reversed(dirs):
new_path = join(top, dirname)
# bpo-23605: os.path.islink() is used instead of caching
# entry.is_symlink() result during the loop on os.scandir() because
# the caller can replace the directory entry during the "yield"
# above.
if followlinks or not islink(new_path):
stack.append(new_path)
if dirs:
prefix = join(top, top[:0]) # Add trailing slash
for dirname in reversed(dirs):
new_path = prefix + dirname
# bpo-23605: os.path.islink() is used instead of caching
# entry.is_symlink() result during the loop on os.scandir() because
# the caller can replace the directory entry during the "yield"
# above.
if followlinks or not islink(new_path):
stack.append(new_path)
else:
# Yield after sub-directory traversal if going bottom up
stack.append((top, dirs, nondirs))
Expand Down Expand Up @@ -766,6 +786,12 @@ def __ror__(self, other):
new.update(self)
return new

if _exists("_clearenv"):
def clear(self):
_clearenv()
self._data.clear()


def _create_environ_mapping():
if name == 'nt':
# Where Env Var Names Must Be UPPERCASE
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@


__all__ = [
"requires_root_user", "requires_non_root_user",
# globals
"PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
# exceptions
Expand Down Expand Up @@ -3336,6 +3337,11 @@ def control_characters_c0() -> list[str]:
return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]


_ROOT_IN_POSIX = hasattr(os, 'geteuid') and os.geteuid() == 0
requires_root_user = unittest.skipUnless(_ROOT_IN_POSIX, "test needs root privilege")
requires_non_root_user = unittest.skipIf(_ROOT_IN_POSIX, "test needs non-root account")


STATUS_DLL_INIT_FAILED = 0xC0000142
def skip_on_low_desktop_heap_memory_subprocess(returncode):
if sys.platform not in ('win32', 'cygwin'):
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_os/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import os.path
from test.support import load_package_tests


def load_tests(*args):
return load_package_tests(os.path.dirname(__file__), *args)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the OS test dependency after the package move

With the OS tests now represented by this package, DEPENDENCIES["os"]["test"] in scripts/update_lib/deps.py:689-693 still names test_os.py. get_test_paths() gives that explicit entry priority, and cmd_quick.py:415-418 warns and skips it when absent, so the next quick update of Lib/os.py will update test_popen.py but leave this entire package stale; change the dependency entry to test_os.

Useful? React with 👍 / 👎.

Loading
Loading