From ae882f798435266b41a9c8966562102345a3eda5 Mon Sep 17 00:00:00 2001 From: Johannes Gijsbers Date: Mon, 30 Aug 2004 10:19:56 +0000 Subject: Patch #941486: add os.path.lexists(). Also fix bug #940578 by using lexists in glob.glob. --- Doc/lib/libglob.tex | 1 + Doc/lib/libposixpath.tex | 9 +++++++++ Lib/glob.py | 4 ++-- Lib/macpath.py | 14 +++++++++++++- Lib/ntpath.py | 3 ++- Lib/os2emxpath.py | 2 ++ Lib/plat-riscos/riscospath.py | 2 ++ Lib/posixpath.py | 11 +++++++++++ Lib/test/test_glob.py | 10 ++++++++++ Lib/test/test_posixpath.py | 2 ++ Misc/NEWS | 3 +++ 11 files changed, 57 insertions(+), 4 deletions(-) diff --git a/Doc/lib/libglob.tex b/Doc/lib/libglob.tex index 5c1de80..0d0d712 100644 --- a/Doc/lib/libglob.tex +++ b/Doc/lib/libglob.tex @@ -21,6 +21,7 @@ which must be a string containing a path specification. \var{pathname} can be either absolute (like \file{/usr/src/Python-1.5/Makefile}) or relative (like \file{../../Tools/*/*.gif}), and can contain shell-style wildcards. +Broken symlinks are included in the results (as in the shell). \end{funcdesc} For example, consider a directory containing only the following files: diff --git a/Doc/lib/libposixpath.tex b/Doc/lib/libposixpath.tex index e79df3e..066a961 100644 --- a/Doc/lib/libposixpath.tex +++ b/Doc/lib/libposixpath.tex @@ -43,6 +43,15 @@ half of the pair returned by \code{split(\var{path})}. \begin{funcdesc}{exists}{path} Return \code{True} if \var{path} refers to an existing path. +Returns \code{False} for broken symbolic links. +\end{funcdesc} + +\begin{funcdesc}{lexists}{path} +Return \code{True} if \var{path} refers to an existing path. +Returns \code{True} for broken symbolic links. +Equivalent to \function{exists()} on platforms lacking +\function{os.lstat()}. +\versionadded{2.4} \end{funcdesc} \begin{funcdesc}{expanduser}{path} diff --git a/Lib/glob.py b/Lib/glob.py index d5e508a..4ba4138 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -13,7 +13,7 @@ def glob(pathname): """ if not has_magic(pathname): - if os.path.exists(pathname): + if os.path.lexists(pathname): return [pathname] else: return [] @@ -29,7 +29,7 @@ def glob(pathname): for dirname in list: if basename or os.path.isdir(dirname): name = os.path.join(dirname, basename) - if os.path.exists(name): + if os.path.lexists(name): result.append(name) else: result = [] diff --git a/Lib/macpath.py b/Lib/macpath.py index 1d3fa56..bca410e 100644 --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -150,7 +150,7 @@ def getctime(filename): return os.stat(filename).st_ctime def exists(s): - """Return True if the pathname refers to an existing file or directory.""" + """Test whether a path exists. Returns False for broken symbolic links""" try: st = os.stat(s) @@ -158,6 +158,18 @@ def exists(s): return False return True +# Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any +# case. + +def lexists(path): + """Test whether a path exists. Returns True for broken symbolic links""" + + try: + st = os.lstat(path) + except os.error: + return False + return True + # Return the longest prefix of all list elements. def commonprefix(m): diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 1f355ec..649e424 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -249,7 +249,6 @@ def islink(path): # Does a path exist? -# This is false for dangling symbolic links. def exists(path): """Test whether a path exists""" @@ -259,6 +258,8 @@ def exists(path): return False return True +lexists = exists + # Is a path a dos directory? # This follows symbolic links, so both islink() and isdir() can be true diff --git a/Lib/os2emxpath.py b/Lib/os2emxpath.py index 9f8a1dd..4c64324 100644 --- a/Lib/os2emxpath.py +++ b/Lib/os2emxpath.py @@ -220,6 +220,8 @@ def exists(path): return False return True +lexists = exists + # Is a path a directory? diff --git a/Lib/plat-riscos/riscospath.py b/Lib/plat-riscos/riscospath.py index 27b5732..97b4f65 100644 --- a/Lib/plat-riscos/riscospath.py +++ b/Lib/plat-riscos/riscospath.py @@ -218,6 +218,8 @@ def exists(p): except swi.error: return 0 +lexists = exists + def isdir(p): """ diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 1a25934..b29eedc 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -174,6 +174,17 @@ def exists(path): return True +# Being true for dangling symbolic links is also useful. + +def lexists(path): + """Test whether a path exists. Returns True for broken symbolic links""" + try: + st = os.lstat(path) + except os.error: + return False + return True + + # Is a path a directory? # This follows symbolic links, so both islink() and isdir() can be true # for the same path. diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index 31de30d..af81dab 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -48,6 +48,9 @@ class GlobTests(unittest.TestCase): self.mktemp('ZZZ') self.mktemp('a', 'bcd', 'EF') self.mktemp('a', 'bcd', 'efg', 'ha') + if hasattr(os, 'symlink'): + os.symlink(self.norm('broken'), self.norm('sym1')) + os.symlink(self.norm('broken'), self.norm('sym2')) def tearDown(self): deltree(self.tempdir) @@ -98,6 +101,13 @@ class GlobTests(unittest.TestCase): eq(self.glob('?a?', '*F'), map(self.norm, [os.path.join('aaa', 'zzzF'), os.path.join('aab', 'F')])) + def test_glob_broken_symlinks(self): + if hasattr(os, 'symlink'): + eq = self.assertSequencesEqual_noorder + eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2')]) + eq(self.glob('sym1'), [self.norm('sym1')]) + eq(self.glob('sym2'), [self.norm('sym2')]) + def test_main(): run_unittest(GlobTests) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py index 1fc3e7c..0a6ed99 100644 --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -150,6 +150,7 @@ class PosixPathTest(unittest.TestCase): os.remove(test_support.TESTFN + "1") self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True) self.assertIs(posixpath.exists(test_support.TESTFN + "2"), False) + self.assertIs(posixpath.lexists(test_support.TESTFN + "2"), True) finally: if not f.close(): f.close() @@ -171,6 +172,7 @@ class PosixPathTest(unittest.TestCase): f.write("foo") f.close() self.assertIs(posixpath.exists(test_support.TESTFN), True) + self.assertIs(posixpath.lexists(test_support.TESTFN), True) finally: if not f.close(): f.close() diff --git a/Misc/NEWS b/Misc/NEWS index 58bd464..1cab304 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -79,6 +79,9 @@ Extension modules Library ------- +- Patch #941486: added os.path.lexists(), which returns True for broken + symlinks, unlike os.path.exists(). + - the random module now uses os.urandom() for seeding if it is available. Added a new generator based on os.urandom(). -- cgit v0.12