8000 gh-99726: Adds os.statx function and associated constants by zooba · Pull Request #99755 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-99726: Adds os.statx function and associated constants #99755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6f7e9fa
gh-99726: Adds os.statx function and associated constants
zooba Nov 24, 2022
21b5f50
Update configure
zooba Nov 24, 2022
8fd982e
Fix POSIX build issues
zooba Nov 24, 2022
2b85372
Revert unrelated pyconfig.h.in changes
zooba Nov 24, 2022
a813f84
Revert generated files
zooba Nov 24, 2022
5a6ce8e
Update pyconfig.h.in
zooba Nov 24, 2022
6f54522
Fixup configure
zooba Nov 24, 2022
cda6886
Fix docs
zooba Nov 24, 2022
0db9341
Check for STATX_MNT_ID
zooba Nov 24, 2022
e278102
Properly exclude statx
zooba Nov 24, 2022
7844111
Add missing fields
zooba Nov 24, 2022
a787ae7
More field initialization
zooba Nov 24, 2022
b1182c3
More uninitialised fields
zooba Nov 24, 2022
cc5a159
endif
zooba Nov 24, 2022
ce24e79
Switch to less-confusing conditional attributes. Other fixes
zooba Nov 25, 2022
4a6e5ee
Few fixes
zooba Nov 25, 2022
7835bde
Make init config tests more reliable on Windows builds
zooba Nov 25, 2022
64111f4
Merge remote-tracking branch 'cpython/main' into gh-99726
zooba Nov 25, 2022
d53c013
Merge remote-tracking branch 'cpython/main' into gh-99726
zooba Nov 28, 2022
991876d
Update DeviceType check and rest of stdlib
zooba Nov 28, 2022
2d90f4d
Fix refleak and tests
zooba Nov 28, 2022
a6d3386
More test fixes
zooba Nov 28, 2022
ed5f370
Fix os.statx assumption
zooba Nov 28, 2022
4e95220
Documentation improvements
zooba Nov 29, 2022
3cc69aa
Missed one doc change
zooba Nov 29, 2022
025a4e6
Nope, it was applied fine
zooba Nov 29, 2022
8ee94aa
Handle block devices better
zooba Nov 29, 2022
bbcc6ee
Put statx in correct os sets, and include in pythoninfo
zooba Nov 29, 2022
768ba42
Merge remote-tracking branch 'cpython/main' into gh-99726
zooba Dec 5, 2022
cadeecb
Merge branch 'main' into gh-99726
carljm Dec 15, 2022
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
Prev Previous commit
Next Next commit
Update DeviceType check and rest of stdlib
  • Loading branch information
zooba committed Nov 28, 2022
commit 991876db24c0fb32565383fd28b88ddcc10d3b8d
8 changes: 4 additions & 4 deletions Lib/filecmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def cmp(f1, f2, shallow=True):

"""

s1 = _sig(os.stat(f1))
s2 = _sig(os.stat(f2))
s1 = _sig(os.statx(f1, stat.STATX_TYPE | stat.STATX_SIZE | stat.STATX_MTIME))
s2 = _sig(os.statx(f2, stat.STATX_TYPE | stat.STATX_SIZE | stat.STATX_MTIME))
if s1[0] != stat.S_IFREG or s2[0] != stat.S_IFREG:
return False
if shallow and s1 == s2:
Expand Down Expand Up @@ -159,12 +159,12 @@ def phase2(self): # Distinguish files, directories, funnies

ok = True
try:
a_stat = os.stat(a_path)
a_stat = os.statx(a_path, stat.STATX_TYPE)
except OSError:
# print('Can\'t stat', a_path, ':', why.args[1])
ok = False
try:
b_stat = os.stat(b_path)
b_stat = os.statx(b_path, stat.STATX_TYPE)
except OSError:
# print('Can\'t stat', b_path, ':', why.args[1])
ok = False
Expand Down
4 changes: 2 additions & 2 deletions Lib/glob.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def _lexists(pathname, dir_fd):
if dir_fd is None:
return os.path.lexists(pathname)
try:
os.lstat(pathname, dir_fd=dir_fd)
os.statx(pathname, stat.STATX_TYPE, dir_fd=dir_fd, follow_symlinks=False)
except (OSError, ValueError):
return False
else:
Expand All @@ -204,7 +204,7 @@ def _isdir(pathname, dir_fd):
if dir_fd is None:
return os.path.isdir(pathname)
try:
st = os.stat(pathname, dir_fd=dir_fd)
st = os.statx(pathname, stat.STATX_TYPE, dir_fd=dir_fd)
except (OSError, ValueError):
return False
else:
Expand Down
7 changes: 4 additions & 3 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,21 @@ def _path_split(path):
return path[:i], path[i + 1:]


def _path_stat(path):
def _path_stat(path, mask=0x0241):
"""Stat the path.

Made a separate function to make it easier to override in experiments
(e.g. cache stat results).

Default mask is STATX_SIZE | STATX_MTIME | STATX_TYPE
"""
return _os.stat(path)
return _os.statx(path, mask)


def _path_is_mode_type(path, mode):
"""Test whether the path is the specified mode type."""
try:
stat_info = _path_stat(path)
stat_info = _path_stat(path, mask=0x01)
except OSError:
return False
return (stat_info.st_mode & 0o170000) == mode
Expand Down
3 changes: 2 additions & 1 deletion Lib/importlib/metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import itertools
import posixpath
import collections
import stat

from . import _adapters, _meta
from ._collections import FreezableDefaultDict, Pair
Expand Down Expand Up @@ -628,7 +629,7 @@ def search(self, name):
@property
def mtime(self):
with suppress(OSError):
return os.stat(self.root).st_mtime
return os.statx(self.root, stat.STATX_MTIME).st_mtime
self.lookup.cache_clear()

@method_cache
Expand Down
8 changes: 4 additions & 4 deletions Lib/logging/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"""

import io, logging, socket, os, pickle, struct, time, re
from stat import ST_DEV, ST_INO, ST_MTIME
from stat import ST_DEV, ST_INO, ST_MTIME, STATX_INO, STATX_MTIME
import queue
import threading
import copy
Expand Down Expand Up @@ -263,7 +263,7 @@ def __init__(self, filename, when='h', interval=1, backupCount=0,
# path object (see Issue #27493), but self.baseFilename will be a string
filename = self.baseFilename
if os.path.exists(filename):
t = os.stat(filename)[ST_MTIME]
t = os.statx(filename, STATX_MTIME)[ST_MTIME]
else:
t = int(time.time())
self.rolloverAt = self.computeRollover(t)
Expand Down Expand Up @@ -484,7 +484,7 @@ def __init__(self, filename, mode='a', encoding=None, delay=False,

def _statstream(self):
if self.stream:
sres = os.fstat(self.stream.fileno())
sres = os.statx(self.stream.fileno(), STATX_INO)
self.dev, self.ino = sres[ST_DEV], sres[ST_INO]

def reopenIfNeeded(self):
Expand All @@ -501,7 +501,7 @@ def reopenIfNeeded(self):
# and patch.
try:
# stat the file by path, checking for existence
sres = os.stat(self.baseFilename)
sres = os.statx(self.baseFilename, STATX_INO)
except FileNotFoundError:
sres = None
# compare file system stat with that of our stream file handle
Expand Down
5 changes: 3 additions & 2 deletions Lib/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import email.generator
import io
import contextlib
import stat
from types import GenericAlias
try:
import fcntl
Expand Down Expand Up< F438 /tool-tip> @@ -499,7 +500,7 @@ def _create_tmp(self):
Maildir._count, hostname)
path = os.path.join(self._path, 'tmp', uniq)
try:
os.stat(path)
os.statx(path, stat.STATX_TYPE)
except FileNotFoundError:
Maildir._count += 1
try:
Expand Down Expand Up @@ -699,7 +700,7 @@ def flush(self):
# self._file is about to get replaced, so no need to sync.
self._file.close()
# Make sure the new file's mode is the same as the old file's
mode = os.stat(self._path).st_mode
mode = os.statx(self._path, stat.STATX_MODE).st_mode
os.chmod(new_file.name, mode)
try:
os.rename(new_file.name, self._path)
Expand Down
36 changes: 20 additions & 16 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from _collections_abc import Sequence
from errno import ENOENT, ENOTDIR, EBADF, ELOOP
from operator import attrgetter
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
from stat import (S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO,
STATX_TYPE, STATX_GID, STATX_UID)
from urllib.parse import quote_from_bytes as urlquote_from_bytes


Expand Down Expand Up @@ -914,25 +915,28 @@ def check_eloop(e):
# Ensure we get an exception by calling stat()
if not strict:
try:
p.stat()
p.stat(mask=STATX_TYPE)
except OSError as e:
check_eloop(e)
return p

def stat(self, *, follow_symlinks=True):
def stat(self, *, follow_symlinks=True, mask=None):
"""
Return the result of the stat() system call on this path, like
os.stat() does.
"""
return os.stat(self, follow_symlinks=follow_symlinks)
if mask is not None:
return os.statx(self, mask, follow_symlinks=follow_symlinks)
else:
return os.stat(self, follow_symlinks=follow_symlinks)

def owner(self):
"""
Return the login name of the file owner.
"""
try:
import pwd
return pwd.getpwuid(self.stat().st_uid).pw_name
return pwd.getpwuid(self.stat(mask=STATX_UID).st_uid).pw_name
except ImportError:
raise NotImplementedError("Path.owner() is unsupported on this system")

Expand All @@ -943,7 +947,7 @@ def group(self):

try:
import grp
return grp.getgrgid(self.stat().st_gid).gr_name
return grp.getgrgid(self.stat(mask=STATX_GID).st_gid).gr_name
except ImportError:
raise NotImplementedError("Path.group() is unsupported on this system")

Expand Down Expand Up @@ -1069,12 +1073,12 @@ def rmdir(self):
"""
os.rmdir(self)

def lstat(self):
def lstat(self, *, mask=None):
"""
Like stat(), except if the path points to a symlink, the symlink's
status information is returned, rather than its target's.
"""
return self.stat(follow_symlinks=False)
return self.stat(follow_symlinks=False, mask=mask)

def rename(self, target):
"""
Expand Down Expand Up @@ -1129,7 +1133,7 @@ def exists(self):
Whether this path exists.
"""
try:
self.stat()
self.stat(mask=STATX_TYPE)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1144,7 +1148,7 @@ def is_dir(self):
Whether this path is a directory.
"""
try:
return S_ISDIR(self.stat().st_mode)
return S_ISDIR(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1161,7 +1165,7 @@ def is_file(self):
to regular files).
"""
try:
return S_ISREG(self.stat().st_mode)
return S_ISREG(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1183,7 +1187,7 @@ def is_symlink(self):
Whether this path is a symbolic link.
"""
try:
return S_ISLNK(self.lstat().st_mode)
return S_ISLNK(self.lstat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1204,7 +1208,7 @@ def is_block_device(self):
Whether this path is a block device.
"""
try:
return S_ISBLK(self.stat().st_mode)
return S_ISBLK(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1220,7 +1224,7 @@ def is_char_device(self):
Whether this path is a character device.
"""
try:
return S_ISCHR(self.stat().st_mode)
return S_ISCHR(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1236,7 +1240,7 @@ def is_fifo(self):
Whether this path is a FIFO.
"""
try:
return S_ISFIFO(self.stat().st_mode)
return S_ISFIFO(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand All @@ -1252,7 +1256,7 @@ def is_socket(self):
Whether this path is a socket.
"""
try:
return S_ISSOCK(self.stat().st_mode)
return S_ISSOCK(self.stat(mask=STATX_TYPE).st_mode)
except OSError as e:
if not _ignore_error(e):
raise
Expand Down
12 changes: 6 additions & 6 deletions Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def dirname(p):
def islink(path):
"""Test whether a path is a symbolic link"""
try:
st = os.lstat(path)
st = os.statx(path, stat.STATX_TYPE, follow_symlinks=False)
except (OSError, ValueError, AttributeError):
return False
return stat.S_ISLNK(st.st_mode)
Expand All @@ -184,7 +184,7 @@ def isjunction(path):
def lexists(path):
"""Test whether a path exists. Returns True for broken symbolic links"""
try:
os.lstat(path)
os.statx(path, stat.STATX_TYPE, follow_symlinks=False)
except (OSError, ValueError):
return False
return True
Expand All @@ -196,7 +196,7 @@ def lexists(path):
def ismount(path):
"""Test whether a path is a mount point"""
try:
s1 = os.lstat(path)
s1 = os.statx(path, stat.STATX_TYPE | stat.STATX_INO, follow_symlinks=False)
except (OSError, ValueError):
# It doesn't exist -- so not a mount point. :-)
return False
Expand All @@ -212,7 +212,7 @@ def ismount(path):
parent = join(path, '..')
parent = realpath(parent)
try:
s2 = os.lstat(parent)
s2 = os.statx(parent, stat.STATX_TYPE | stat.STATX_INO, follow_symlinks=False)
except (OSError, ValueError):
return False

Expand Down Expand Up @@ -458,7 +458,7 @@ def _joinrealpath(path, rest, strict, seen):
continue
newpath = join(path, name)
try:
st = os.lstat(newpath)
st = os.statx(newpath, stat.STATX_TYPE, follow_symlinks=False)
except OSError:
if strict:
raise
Expand All @@ -478,7 +478,7 @@ def _joinrealpath(path, rest, strict, seen):
# The symlink is not resolved, so we must have a symlink loop.
if strict:
# Raise OSError(errno.ELOOP)
os.stat(newpath)
os.statx(newpath, stat.STATX_TYPE)
else:
# Return already resolved part + rest of the path unchanged.
return join(newpath, rest), False
Expand Down
3 changes: 2 additions & 1 deletion Lib/pstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import sys
import os
import stat
import time
import marshal
import re
Expand Down Expand Up @@ -142,7 +143,7 @@ def load_stats(self, arg):
with open(arg, 'rb') as f:
self.stats = marshal.load(f)
try:
file_stats = os.stat(arg)
file_stats = os.statx(arg, stat.STATX_MTIME)
arg = time.ctime(file_stats.st_mtime) + " " + arg
except: # in case this is not unix
pass
Expand Down
3 changes: 2 additions & 1 deletion Lib/pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class or function within a module or module in a package. If the
import pkgutil
import platform
import re
import stat
import sys
import sysconfig
import time
Expand Down Expand Up @@ -349,7 +350,7 @@ def source_synopsis(file):

def synopsis(filename, cache={}):
"""Get the one-line summary out of a module file."""
mtime = os.stat(filename).st_mtime
mtime = os.statx(filename, stat.STATX_MTIME).st_mtime
lastupdate, result = cache.get(filename, (None, None))
if lastupdate is None or lastupdate < mtime:
# Look for binary suffixes first, falling back to source.
Expand Down
Loading
0