[Python-Dev] Issue 11406: adding os.scandir(), a directory iterator returning stat-like info (original) (raw)

Christian Heimes christian at python.org
Mon May 13 01:28:33 CEST 2013


Am 13.05.2013 00:04, schrieb Ben Hoyt:

In fact, I don't think .cachedlstat should be exposed to the user. They just call entry.lstat(), and it returns a cached stat or calls os.lstat() to get the real stat if required (and populates the internal cached stat value). And the entry.is* functions would call entry.lstat() if dirent was or dtype was DTUNKNOWN. This would change relatively nasty code like this:

I would prefer to go the other route and don't expose lstat(). It's cleaner and less confusing to have a property cached_lstat on the object because it actually says what it contains. The property's internal code can do a lstat() call if necessary.

Your code example doesn't handle the case of a failing lstat() call. It can happen when the file is removed or permission of a parent directory changes.

This change would make scandir() usable by ordinary mortals, rather than just hardcore library implementors.

Why not have both? The os module exposes and leaks the platform details on more than on occasion. A low level function can expose name + dirent struct on POSIX and name + stat_result on Windows. Then you can build a high level API like os.scandir() in pure Python code.

class DirEntry: def init(self, name, dirent, lstat, path='.'): # User shouldn't need to call this, but called internally by scandir() self.name = name self.dirent = dirent self.lstat = lstat # non-public attributes self.path = path

You should include the fd of the DIR pointer here for the new *at() function family.

def lstat(self): if self.lstat is None: self.lstat = os.lstat(os.path.join(self.path, self.name)) return self.lstat

The function should use fstatat(2) function (os.lstat with dir_fd) when it is available on the current platform. It's better and more secure than lstat() with a joined path.

def isdir(self): if self.dirent is not None and self.dirent.dtype != DTUNKNOWN: return self.dirent.dtype == DTDIR else: return stat.SISDIR(self.lstat().stmode)

def isfile(self): if self.dirent is not None and self.dirent.dtype != DTUNKNOWN: return self.dirent.dtype == DTREG else: return stat.SISREG(self.lstat().stmode) def islink(self): if self.dirent is not None and self.dirent.dtype != DTUNKNOWN: return self.dirent.dtype == DTLNK else: return stat.SISLNK(self.lstat().stmode)

A bit faster:

d_type = getattr(self.dirent, "d_type", DT_UNKNOWN)
if d_type != DT_UNKNOWN:
    return d_type == DT_LNK

The code doesn't handle a failing lstat() call.

Christian



More information about the Python-Dev mailing list