From d5eaec271ac1c910f861b6548172e3c3c69f9c6e Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Tue, 27 Nov 2012 21:53:07 +1300 Subject: [PATCH] Simplify benchmark's os_listdir so it's more like os.listdir() would do --- benchmark.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++----- betterwalk.py | 2 +- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/benchmark.py b/benchmark.py index 2c31448..9bf3eee 100644 --- a/benchmark.py +++ b/benchmark.py @@ -12,11 +12,62 @@ NUM_DIRS = 5 NUM_FILES = 50 -def os_listdir(path): - """Identical to os.listdir(), but use iterdir_stat() to get data so we're - using ctypes-based system calls to benchmark against. - """ - return [name for name, st in betterwalk.iterdir_stat(path)] +# ctypes versions of os.listdir() so benchmark can compare apples with apples +if sys.platform == 'win32': + import ctypes + from ctypes import wintypes + + def os_listdir(path): + data = wintypes.WIN32_FIND_DATAW() + data_p = ctypes.byref(data) + filename = os.path.join(path, '*') + handle = betterwalk.FindFirstFile(filename, data_p) + if handle == betterwalk.INVALID_HANDLE_VALUE: + error = ctypes.GetLastError() + if error == betterwalk.ERROR_FILE_NOT_FOUND: + return [] + raise betterwalk.win_error(error, path) + names = [] + try: + while True: + name = data.cFileName + if name not in ('.', '..'): + names.append(name) + success = betterwalk.FindNextFile(handle, data_p) + if not success: + error = ctypes.GetLastError() + if error == betterwalk.ERROR_NO_MORE_FILES: + break + raise betterwalk.win_error(error, path) + finally: + if not betterwalk.FindClose(handle): + raise betterwalk.win_error(ctypes.GetLastError(), path) + return names + +elif sys.platform.startswith(('linux', 'darwin')) or 'bsd' in sys.platform: + def os_listdir(path): + dir_p = betterwalk.opendir(path.encode(betterwalk.file_system_encoding)) + if not dir_p: + raise betterwalk.posix_error(path) + names = [] + try: + entry = betterwalk.dirent() + result = betterwalk.dirent_p() + while True: + if betterwalk.readdir_r(dir_p, entry, result): + raise betterwalk.posix_error(path) + if not result: + break + name = entry.d_name.decode(betterwalk.file_system_encoding) + if name not in ('.', '..'): + names.append(name) + finally: + if betterwalk.closedir(dir_p): + raise betterwalk.posix_error(path) + return names + +else: + raise NotImplementedError def os_walk(top, topdown=True, onerror=None, followlinks=False): """Identical to os.walk(), but use ctypes-based listdir() so benchmark @@ -24,7 +75,7 @@ def os_walk(top, topdown=True, onerror=None, followlinks=False): """ try: names = os_listdir(top) - except error as err: + except OSError as err: if onerror is not None: onerror(err) return diff --git a/betterwalk.py b/betterwalk.py index ea56791..4ba3d28 100644 --- a/betterwalk.py +++ b/betterwalk.py @@ -113,7 +113,7 @@ def iterdir_stat(path='.', pattern='*', fields=None): wildcard = pattern pattern = None - # Call FindFirstFile and errors + # Call FindFirstFile and handle errors data = wintypes.WIN32_FIND_DATAW() data_p = ctypes.byref(data) filename = os.path.join(path, wildcard)