[pypy-svn] r76189 - in pypy/branch/unicode_filename-2/pypy: module/posix rlib rlib/test rpython/module

afa at codespeak.net afa at codespeak.net
Tue Jul 13 18:41:22 CEST 2010


Author: afa
Date: Tue Jul 13 18:41:20 2010
New Revision: 76189

Modified:
   pypy/branch/unicode_filename-2/pypy/module/posix/interp_posix.py
   pypy/branch/unicode_filename-2/pypy/rlib/rposix.py
   pypy/branch/unicode_filename-2/pypy/rlib/rwin32.py
   pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py
   pypy/branch/unicode_filename-2/pypy/rpython/module/ll_os.py
Log:
Implement win32 unicode version of os.listdir()


Modified: pypy/branch/unicode_filename-2/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/module/posix/interp_posix.py	(original)
+++ pypy/branch/unicode_filename-2/pypy/module/posix/interp_posix.py	Tue Jul 13 18:41:20 2010
@@ -434,7 +434,7 @@
 unsetenv.unwrap_spec = [ObjSpace, str]
 
 
-def listdir(space, dirname):
+def listdir(space, w_dirname):
     """Return a list containing the names of the entries in the directory.
 
 \tpath: path of directory to list
@@ -442,12 +442,18 @@
 The list is in arbitrary order.  It does not include the special
 entries '.' and '..' even if they are present in the directory."""
     try:
-        result = os.listdir(dirname)
+        if space.isinstance_w(w_dirname, space.w_unicode):
+            dirname = FileEncoder(space, w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
+        else:
+            dirname = space.str_w(w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
     except OSError, e:
-        raise wrap_oserror(space, e, dirname)
-    result_w = [space.wrap(s) for s in result]
+        raise wrap_oserror2(space, e, w_dirname)
     return space.newlist(result_w)
-listdir.unwrap_spec = [ObjSpace, str]
+listdir.unwrap_spec = [ObjSpace, W_Root]
 
 def pipe(space):
     "Create a pipe.  Returns (read_end, write_end)."

Modified: pypy/branch/unicode_filename-2/pypy/rlib/rposix.py
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rlib/rposix.py	(original)
+++ pypy/branch/unicode_filename-2/pypy/rlib/rposix.py	Tue Jul 13 18:41:20 2010
@@ -74,3 +74,10 @@
         return os.unlink(path)
     else:
         return os.unlink(path.encode())
+
+ at specialize.argtype(0)
+def listdir(dirname):
+    if isinstance(dirname, str):
+        return os.listdir(dirname)
+    else:
+        return os.listdir(dirname.encode())

Modified: pypy/branch/unicode_filename-2/pypy/rlib/rwin32.py
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rlib/rwin32.py	(original)
+++ pypy/branch/unicode_filename-2/pypy/rlib/rwin32.py	Tue Jul 13 18:41:20 2010
@@ -31,6 +31,7 @@
         DWORD = rffi_platform.SimpleType("DWORD", rffi.UINT)
         BOOL = rffi_platform.SimpleType("BOOL", rffi.LONG)
         BYTE = rffi_platform.SimpleType("BYTE", rffi.UCHAR)
+        WCHAR = rffi_platform.SimpleType("WCHAR", rffi.UCHAR)
         INT = rffi_platform.SimpleType("INT", rffi.INT)
         LONG = rffi_platform.SimpleType("LONG", rffi.LONG)
         PLONG = rffi_platform.SimpleType("PLONG", rffi.LONGP)
@@ -38,6 +39,7 @@
         LPCVOID = rffi_platform.SimpleType("LPCVOID", rffi.VOIDP)
         LPSTR = rffi_platform.SimpleType("LPSTR", rffi.CCHARP)
         LPCSTR = rffi_platform.SimpleType("LPCSTR", rffi.CCHARP)
+        LPCWSTR = rffi_platform.SimpleType("LPCWSTR", rffi.CWCHARP)
         LPDWORD = rffi_platform.SimpleType("LPDWORD", rffi.INTP)
         SIZE_T = rffi_platform.SimpleType("SIZE_T", rffi.SIZE_T)
         ULONG_PTR = rffi_platform.SimpleType("ULONG_PTR", rffi.ULONG)
@@ -87,6 +89,10 @@
     GetLastError = winexternal('GetLastError', [], DWORD)
     SetLastError = winexternal('SetLastError', [DWORD], lltype.Void)
 
+    # In tests, the first call to GetLastError is always wrong, because error
+    # is hidden by operations in ll2ctypes.  Call it now.
+    GetLastError()
+
     LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], rffi.VOIDP)
     GetProcAddress = winexternal('GetProcAddress',
                                  [rffi.VOIDP, rffi.CCHARP],

Modified: pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py	(original)
+++ pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py	Tue Jul 13 18:41:20 2010
@@ -1,11 +1,23 @@
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.tool.udir import udir
 from pypy.rlib import rposix
-import os
+import os, sys
 
 def ll_to_string(s):
     return ''.join(s.chars)
 
+class UnicodeWithEncoding:
+    def __init__(self, unistr):
+        self.unistr = unistr
+
+    def encode(self):
+        from pypy.rlib.runicode import unicode_encode_utf_8
+        return unicode_encode_utf_8(self.unistr, len(self.unistr),
+                                    "strict")
+
+    def gettext(self):
+        return self.unistr
+
 class TestPosixUnicode:
     def setup_method(self, method):
         self.ufilename = (unicode(udir.join('test_open')) +
@@ -14,18 +26,6 @@
         f.write("test")
         f.close()
 
-        class UnicodeWithEncoding:
-            def __init__(self, unistr):
-                self.unistr = unistr
-
-            def encode(self):
-                from pypy.rlib.runicode import unicode_encode_utf_8
-                return unicode_encode_utf_8(self.unistr, len(self.unistr),
-                                            "strict")
-
-            def gettext(self):
-                return self.unistr
-
         self.path = UnicodeWithEncoding(self.ufilename)
 
     def test_access(self):
@@ -54,3 +54,11 @@
 
         interpret(f, [])
         assert not os.path.exists(self.ufilename)
+
+    def test_listdir(self):
+        udir = UnicodeWithEncoding(os.path.dirname(self.ufilename))
+        def f():
+            return u', '.join(rposix.listdir(udir))
+
+        result = interpret(f, [])
+        assert os.path.basename(self.ufilename) in ll_to_string(result)

Modified: pypy/branch/unicode_filename-2/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rpython/module/ll_os.py	(original)
+++ pypy/branch/unicode_filename-2/pypy/rpython/module/ll_os.py	Tue Jul 13 18:41:20 2010
@@ -1035,10 +1035,10 @@
             ERROR_NO_MORE_FILES  = config['ERROR_NO_MORE_FILES']
             LPWIN32_FIND_DATA    = lltype.Ptr(WIN32_FIND_DATA)
 
-            FindFirstFile = self.llexternal('FindFirstFile',
+            FindFirstFile = self.llexternal('FindFirstFileA',
                                             [rwin32.LPCSTR, LPWIN32_FIND_DATA],
                                             rwin32.HANDLE)
-            FindNextFile = self.llexternal('FindNextFile',
+            FindNextFile = self.llexternal('FindNextFileA',
                                            [rwin32.HANDLE, LPWIN32_FIND_DATA],
                                            rwin32.BOOL)
             FindClose = self.llexternal('FindClose',
@@ -1122,6 +1122,73 @@
                       "ll_os.ll_os_listdir",
                       llimpl=os_listdir_llimpl)
 
+    @registering_unicode_version(os.listdir, 1, [0], sys.platform=='win32')
+    def register_os_listdir_unicode(self):
+        from pypy.rlib import rwin32
+        class CConfig:
+            _compilation_info_ = ExternalCompilationInfo(
+                includes = ['windows.h']
+            )
+            WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAW',
+                [('cFileName', lltype.FixedSizeArray(rwin32.WCHAR, 250))])
+            ERROR_FILE_NOT_FOUND = platform.ConstantInteger(
+                'ERROR_FILE_NOT_FOUND')
+            ERROR_NO_MORE_FILES = platform.ConstantInteger(
+                'ERROR_NO_MORE_FILES')
+
+        config = platform.configure(CConfig)
+        WIN32_FIND_DATA      = config['WIN32_FIND_DATA']
+        ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND']
+        ERROR_NO_MORE_FILES  = config['ERROR_NO_MORE_FILES']
+        LPWIN32_FIND_DATA    = lltype.Ptr(WIN32_FIND_DATA)
+
+        FindFirstFile = self.llexternal('FindFirstFileW',
+                                        [rwin32.LPCWSTR, LPWIN32_FIND_DATA],
+                                        rwin32.HANDLE)
+        FindNextFile = self.llexternal('FindNextFileW',
+                                       [rwin32.HANDLE, LPWIN32_FIND_DATA],
+                                       rwin32.BOOL)
+        FindClose = self.llexternal('FindClose',
+                                    [rwin32.HANDLE],
+                                    rwin32.BOOL)
+
+        def os_listdir_llimpl(path):
+            if path and path[-1] not in (u'/', u'\\', u':'):
+                path += u'/'
+            path += u'*.*'
+            filedata = lltype.malloc(WIN32_FIND_DATA, flavor='raw')
+            try:
+                result = []
+                hFindFile = FindFirstFile(path, filedata)
+                if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+                    error = rwin32.GetLastError()
+                    if error == ERROR_FILE_NOT_FOUND:
+                        return result
+                    else:
+                        raise WindowsError(error,  "FindFirstFile failed")
+                while True:
+                    name = rffi.wcharp2unicode(rffi.cast(rffi.CWCHARP,
+                                                         filedata.c_cFileName))
+                    if name != u"." and name != u"..":   # skip these
+                        result.append(name)
+                    if not FindNextFile(hFindFile, filedata):
+                        break
+                # FindNextFile sets error to ERROR_NO_MORE_FILES if
+                # it got to the end of the directory
+                error = rwin32.GetLastError()
+                FindClose(hFindFile)
+                if error == ERROR_NO_MORE_FILES:
+                    return result
+                else:
+                    raise WindowsError(error,  "FindNextFile failed")
+            finally:
+                lltype.free(filedata, flavor='raw')
+
+        return extdef([unicode],  # a single argument which is a unicode
+                      [unicode],  # returns a list of unicodes
+                      "ll_os.ll_os_wlistdir",
+                      llimpl=os_listdir_llimpl)
+
     @registering(os.pipe)
     def register_os_pipe(self):
         # we need a different approach on Windows and on Posix



More information about the Pypy-commit mailing list