[pypy-commit] pypy default: Start writing an RPython interface that should allow us to portably
arigo
pypy.commits at gmail.com
Sun Aug 21 14:23:18 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r86374:e139e4ad76df
Date: 2016-08-21 18:58 +0200
http://bitbucket.org/pypy/pypy/changeset/e139e4ad76df/
Log: Start writing an RPython interface that should allow us to portably
implement os.scandir() in py3.5
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -250,6 +250,7 @@
OFF_T_SIZE = rffi_platform.SizeOf('off_t')
HAVE_UTIMES = rffi_platform.Has('utimes')
+ HAVE_D_TYPE = rffi_platform.Has('DT_UNKNOWN')
UTIMBUF = rffi_platform.Struct('struct %sutimbuf' % UNDERSCORE_ON_WIN32,
[('actime', rffi.INT),
('modtime', rffi.INT)])
@@ -603,11 +604,17 @@
class CConfig:
_compilation_info_ = eci
DIRENT = rffi_platform.Struct('struct dirent',
- [('d_name', lltype.FixedSizeArray(rffi.CHAR, 1))])
+ [('d_name', lltype.FixedSizeArray(rffi.CHAR, 1))]
+ + [('d_type', rffi.INT)] if HAVE_D_TYPE else [])
+ if HAVE_D_TYPE:
+ DT_UNKNOWN = rffi_platform.ConstantInteger('DT_UNKNOWN')
+ DT_REG = rffi_platform.ConstantInteger('DT_REG')
+ DT_DIR = rffi_platform.ConstantInteger('DT_DIR')
+ DT_LNK = rffi_platform.ConstantInteger('DT_LNK')
DIRP = rffi.COpaquePtr('DIR')
- config = rffi_platform.configure(CConfig)
- DIRENT = config['DIRENT']
+ dirent_config = rffi_platform.configure(CConfig)
+ DIRENT = dirent_config['DIRENT']
DIRENTP = lltype.Ptr(DIRENT)
c_opendir = external('opendir',
[rffi.CCHARP], DIRP, save_err=rffi.RFFI_SAVE_ERRNO)
@@ -617,7 +624,9 @@
# dirent struct (which depends on defines)
c_readdir = external('readdir', [DIRP], DIRENTP,
macro=True, save_err=rffi.RFFI_FULL_ERRNO_ZERO)
- c_closedir = external('closedir', [DIRP], rffi.INT)
+ c_closedir = external('closedir', [DIRP], rffi.INT, releasegil=False)
+else:
+ dirent_config = {}
def _listdir(dirp):
result = []
diff --git a/rpython/rlib/rposix_scandir.py b/rpython/rlib/rposix_scandir.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rposix_scandir.py
@@ -0,0 +1,59 @@
+from rpython.rlib import rposix
+from rpython.rlib.objectmodel import specialize
+from rpython.rtyper.lltypesystem import rffi
+
+
+ at specialize.argtype(0)
+def opendir(path):
+ path = rposix._as_bytes0(path)
+ return opendir_bytes(path)
+
+def opendir_bytes(path):
+ dirp = rposix.c_opendir(path)
+ if not dirp:
+ raise OSError(rposix.get_saved_errno(), "opendir failed")
+ return dirp
+
+def closedir(dirp):
+ rposix.c_closedir(dirp)
+
+def nextentry(dirp):
+ """Read the next entry and returns an opaque object.
+ Use the methods has_xxx() and get_xxx() to read from that
+ opaque object. The opaque object is valid until the next
+ time nextentry() or closedir() is called. This may raise
+ StopIteration, or OSError. Note that this doesn't filter
+ out the "." and ".." entries.
+ """
+ direntp = rposix.c_readdir(dirp)
+ if direntp:
+ return direntp
+ error = rposix.get_saved_errno()
+ if error:
+ raise OSError(error, "readdir failed")
+ raise StopIteration
+
+def has_name_bytes(direntp):
+ return True
+
+def get_name_bytes(direntp):
+ namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
+ return rffi.charp2str(namep)
+
+DT_UNKNOWN = rposix.dirent_config.get('DT_UNKNOWN', None)
+DT_REG = rposix.dirent_config.get('DT_REG', None)
+DT_DIR = rposix.dirent_config.get('DT_DIR', None)
+DT_LNK = rposix.dirent_config.get('DT_LNK', None)
+
+def has_type(direntp):
+ return (DT_UNKNOWN is not None and
+ rffi.getintfield(direntp, 'c_d_type') != DT_UNKNOWN)
+
+def type_is_regular(direntp):
+ return rffi.getintfield(direntp, 'c_d_type') == DT_REG
+
+def type_is_dir(direntp):
+ return rffi.getintfield(direntp, 'c_d_type') == DT_DIR
+
+def type_is_link(direntp):
+ return rffi.getintfield(direntp, 'c_d_type') == DT_LNK
diff --git a/rpython/rlib/test/test_rposix_scandir.py b/rpython/rlib/test/test_rposix_scandir.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/test_rposix_scandir.py
@@ -0,0 +1,22 @@
+import sys, os
+import py
+from rpython.rlib import rposix_scandir
+
+
+class TestScanDir(object):
+
+ @py.test.mark.skipif("sys.platform == 'win32'") # XXX
+ def test_name_bytes(self):
+ scan = rposix_scandir.opendir('/')
+ found = []
+ while True:
+ try:
+ p = rposix_scandir.nextentry(scan)
+ except StopIteration:
+ break
+ assert rposix_scandir.has_name_bytes(p)
+ found.append(rposix_scandir.get_name_bytes(p))
+ rposix_scandir.closedir(scan)
+ found.remove('.')
+ found.remove('..')
+ assert sorted(found) == sorted(os.listdir('/'))
More information about the pypy-commit
mailing list