- Move functions common to all path modules into genericpath.py and have the

OS speicifc path modules import them.
- Have os2emxpath import common functions fron ntpath instead of using copies
This commit is contained in:
Jack Diederich 2006-08-26 18:42:06 +00:00
parent 4582d7d905
commit 7b60464ceb
6 changed files with 273 additions and 476 deletions

78
Lib/genericpath.py Normal file
View File

@ -0,0 +1,78 @@
"""
Path operations common to more than one OS
Do not use directly. The OS specific modules import the appropriate
functions from this module themselves.
"""
import os
import stat
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
'getsize', 'isdir', 'isfile']
# Does a path exist?
# This is false for dangling symbolic links on systems that support them.
def exists(path):
"""Test whether a path exists. Returns False for broken symbolic links"""
try:
st = os.stat(path)
except os.error:
return False
return True
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path ono systems that support symlinks
def isfile(path):
"""Test whether a path is a regular file"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISREG(st.st_mode)
# Is a path a directory?
# This follows symbolic links, so both islink() and isdir()
# can be true for the same path on systems that support symlinks
def isdir(s):
"""Return true if the pathname refers to an existing directory."""
try:
st = os.stat(s)
except os.error:
return False
return stat.S_ISDIR(st.st_mode)
def getsize(filename):
"""Return the size of a file, reported by os.stat()."""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the metadata change time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
s1 = min(m)
s2 = max(m)
n = min(len(s1), len(s2))
for i in xrange(n):
if s1[i] != s2[i]:
return s1[:i]
return s1[:n]

View File

@ -2,6 +2,7 @@
import os
from stat import *
from genericpath import *
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
@ -101,31 +102,6 @@ def ismount(s):
components = split(s)
return len(components) == 2 and components[1] == ''
def isdir(s):
"""Return true if the pathname refers to an existing directory."""
try:
st = os.stat(s)
except os.error:
return 0
return S_ISDIR(st.st_mode)
# Get size, mtime, atime of files.
def getsize(filename):
"""Return the size of a file, reported by os.stat()."""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
return os.stat(filename).st_atime
def islink(s):
"""Return true if the pathname refers to a symbolic link."""
@ -135,29 +111,6 @@ def islink(s):
except:
return False
def isfile(s):
"""Return true if the pathname refers to an existing regular file."""
try:
st = os.stat(s)
except os.error:
return False
return S_ISREG(st.st_mode)
def getctime(filename):
"""Return the creation time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
def exists(s):
"""Test whether a path exists. Returns False for broken symbolic links"""
try:
st = os.stat(s)
except os.error:
return False
return True
# Is `stat`/`lstat` a meaningful difference on the Mac? This is safe in any
# case.
@ -170,20 +123,6 @@ def lexists(path):
return False
return True
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
s1 = min(m)
s2 = max(m)
n = min(len(s1), len(s2))
for i in xrange(n):
if s1[i] != s2[i]:
return s1[:i]
return s1[:n]
def expandvars(path):
"""Dummy to retain interface-compatibility with other operating systems."""
return path

View File

@ -8,6 +8,7 @@ module as os.path.
import os
import stat
import sys
from genericpath import *
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
@ -206,86 +207,18 @@ def dirname(p):
"""Returns the directory component of a pathname"""
return split(p)[0]
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
s1 = min(m)
s2 = max(m)
n = min(len(s1), len(s2))
for i in xrange(n):
if s1[i] != s2[i]:
return s1[:i]
return s1[:n]
# Get size, mtime, atime of files.
def getsize(filename):
"""Return the size of a file, reported by os.stat()"""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()"""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()"""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the creation time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
# Is a path a symbolic link?
# This will always return false on systems where posix.lstat doesn't exist.
def islink(path):
"""Test for symbolic link. On WindowsNT/95 always returns false"""
"""Test for symbolic link.
On WindowsNT/95 and OS/2 always returns false
"""
return False
# Does a path exist?
def exists(path):
"""Test whether a path exists"""
try:
st = os.stat(path)
except os.error:
return False
return True
# alias exists to lexists
lexists = exists
# Is a path a dos directory?
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path.
def isdir(path):
"""Test whether a path is a directory"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISDIR(st.st_mode)
# Is a path a regular file?
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path.
def isfile(path):
"""Test whether a path is a regular file"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISREG(st.st_mode)
# Is a path a mount point? Either a root (with or without drive letter)
# or an UNC path with at most a / or \ after the mount point.

View File

@ -7,6 +7,9 @@ module as os.path.
import os
import stat
from genericpath import *
from ntpath import (expanduser, expandvars, isabs, islink, splitdrive,
splitext, split, walk)
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
@ -36,18 +39,6 @@ def normcase(s):
return s.replace('\\', '/').lower()
# Return whether a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS.
# For DOS it is absolute if it starts with a slash or backslash (current
# volume), or if a pathname after the volume letter and colon / UNC resource
# starts with a slash or backslash.
def isabs(s):
"""Test whether a path is absolute"""
s = splitdrive(s)[1]
return s != '' and s[:1] in '/\\'
# Join two (or more) paths.
def join(a, *p):
@ -63,17 +54,6 @@ def join(a, *p):
return path
# Split a path in a drive specification (a drive letter followed by a
# colon) and the path specification.
# It is always true that drivespec + pathspec == p
def splitdrive(p):
"""Split a pathname into drive and path specifiers. Returns a 2-tuple
"(drive,path)"; either part may be empty"""
if p[1:2] == ':':
return p[0:2], p[2:]
return '', p
# Parse UNC paths
def splitunc(p):
"""Split a pathname into UNC mount point and relative path specifiers.
@ -103,57 +83,6 @@ def splitunc(p):
return '', p
# Split a path in head (everything up to the last '/') and tail (the
# rest). After the trailing '/' is stripped, the invariant
# join(head, tail) == p holds.
# The resulting head won't end in '/' unless it is the root.
def split(p):
"""Split a pathname.
Return tuple (head, tail) where tail is everything after the final slash.
Either part may be empty."""
d, p = splitdrive(p)
# set i to index beyond p's last slash
i = len(p)
while i and p[i-1] not in '/\\':
i = i - 1
head, tail = p[:i], p[i:] # now tail has no slashes
# remove trailing slashes from head, unless it's all slashes
head2 = head
while head2 and head2[-1] in '/\\':
head2 = head2[:-1]
head = head2 or head
return d + head, tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def splitext(p):
"""Split the extension from a pathname.
Extension is everything from the last dot to the end.
Return (root, ext), either part may be empty."""
root, ext = '', ''
for c in p:
if c in ['/','\\']:
root, ext = root + ext + c, ''
elif c == '.':
if ext:
root, ext = root + ext, c
else:
ext = c
elif ext:
ext = ext + c
else:
root = root + c
return root, ext
# Return the tail (basename) part of a path.
def basename(p):
@ -168,84 +97,12 @@ def dirname(p):
return split(p)[0]
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
s1 = min(m)
s2 = max(m)
n = min(len(s1), len(s2))
for i in xrange(n):
if s1[i] != s2[i]:
return s1[:i]
return s1[:n]
# Get size, mtime, atime of files.
def getsize(filename):
"""Return the size of a file, reported by os.stat()"""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()"""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()"""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the creation time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
# Is a path a symbolic link?
# This will always return false on systems where posix.lstat doesn't exist.
def islink(path):
"""Test for symbolic link. On OS/2 always returns false"""
return False
# Does a path exist?
# This is false for dangling symbolic links.
def exists(path):
"""Test whether a path exists"""
try:
st = os.stat(path)
except os.error:
return False
return True
# alias exists to lexists
lexists = exists
# Is a path a directory?
def isdir(path):
"""Test whether a path is a directory"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISDIR(st.st_mode)
# Is a path a regular file?
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path.
def isfile(path):
"""Test whether a path is a regular file"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISREG(st.st_mode)
# Is a path a mount point? Either a root (with or without drive letter)
# or an UNC path with at most a / or \ after the mount point.
@ -258,131 +115,6 @@ def ismount(path):
return len(p) == 1 and p[0] in '/\\'
# Directory tree walk.
# For each directory under top (including top itself, but excluding
# '.' and '..'), func(arg, dirname, filenames) is called, where
# dirname is the name of the directory and filenames is the list
# of files (and subdirectories etc.) in the directory.
# The func may modify the filenames list, to implement a filter,
# or to impose a different order of visiting.
def walk(top, func, arg):
"""Directory tree walk whth callback function.
walk(top, func, arg) calls func(arg, d, files) for each directory d
in the tree rooted at top (including top itself); files is a list
of all the files and subdirs in directory d."""
try:
names = os.listdir(top)
except os.error:
return
func(arg, top, names)
exceptions = ('.', '..')
for name in names:
if name not in exceptions:
name = join(top, name)
if isdir(name):
walk(name, func, arg)
# Expand paths beginning with '~' or '~user'.
# '~' means $HOME; '~user' means that user's home directory.
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
# the path is returned unchanged (leaving error reporting to whatever
# function is called with the expanded path as argument).
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
# (A function should also be defined to do full *sh-style environment
# variable expansion.)
def expanduser(path):
"""Expand ~ and ~user constructs.
If user or $HOME is unknown, do nothing."""
if path[:1] != '~':
return path
i, n = 1, len(path)
while i < n and path[i] not in '/\\':
i = i + 1
if i == 1:
if 'HOME' in os.environ:
userhome = os.environ['HOME']
elif not 'HOMEPATH' in os.environ:
return path
else:
try:
drive = os.environ['HOMEDRIVE']
except KeyError:
drive = ''
userhome = join(drive, os.environ['HOMEPATH'])
else:
return path
return userhome + path[i:]
# Expand paths containing shell variable substitutions.
# The following rules apply:
# - no expansion within single quotes
# - no escape character, except for '$$' which is translated into '$'
# - ${varname} is accepted.
# - varnames can be made out of letters, digits and the character '_'
# XXX With COMMAND.COM you can use any characters in a variable name,
# XXX except '^|<>='.
def expandvars(path):
"""Expand shell variables of form $var and ${var}.
Unknown variables are left unchanged."""
if '$' not in path:
return path
import string
varchars = string.letters + string.digits + '_-'
res = ''
index = 0
pathlen = len(path)
while index < pathlen:
c = path[index]
if c == '\'': # no expansion within single quotes
path = path[index + 1:]
pathlen = len(path)
try:
index = path.index('\'')
res = res + '\'' + path[:index + 1]
except ValueError:
res = res + path
index = pathlen - 1
elif c == '$': # variable or '$$'
if path[index + 1:index + 2] == '$':
res = res + c
index = index + 1
elif path[index + 1:index + 2] == '{':
path = path[index+2:]
pathlen = len(path)
try:
index = path.index('}')
var = path[:index]
if var in os.environ:
res = res + os.environ[var]
except ValueError:
res = res + path
index = pathlen - 1
else:
var = ''
index = index + 1
c = path[index:index + 1]
while c != '' and c in varchars:
var = var + c
index = index + 1
c = path[index:index + 1]
if var in os.environ:
res = res + os.environ[var]
if c != '':
res = res + c
else:
res = res + c
index = index + 1
return res
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
def normpath(path):

View File

@ -12,6 +12,7 @@ for manipulation of the pathname component of URLs.
import os
import stat
from genericpath import *
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
@ -119,37 +120,6 @@ def dirname(p):
return split(p)[0]
# Return the longest prefix of all list elements.
def commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
s1 = min(m)
s2 = max(m)
n = min(len(s1), len(s2))
for i in xrange(n):
if s1[i] != s2[i]:
return s1[:i]
return s1[:n]
# Get size, mtime, atime of files.
def getsize(filename):
"""Return the size of a file, reported by os.stat()."""
return os.stat(filename).st_size
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the metadata change time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
# Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist.
@ -161,19 +131,6 @@ def islink(path):
return False
return stat.S_ISLNK(st.st_mode)
# Does a path exist?
# This is false for dangling symbolic links.
def exists(path):
"""Test whether a path exists. Returns False for broken symbolic links"""
try:
st = os.stat(path)
except os.error:
return False
return True
# Being true for dangling symbolic links is also useful.
def lexists(path):
@ -185,32 +142,6 @@ def lexists(path):
return True
# Is a path a directory?
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path.
def isdir(path):
"""Test whether a path is a directory"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISDIR(st.st_mode)
# Is a path a regular file?
# This follows symbolic links, so both islink() and isfile() can be true
# for the same path.
def isfile(path):
"""Test whether a path is a regular file"""
try:
st = os.stat(path)
except os.error:
return False
return stat.S_ISREG(st.st_mode)
# Are two filenames really pointing to the same file?
def samefile(f1, f2):

View File

@ -0,0 +1,184 @@
import unittest
from test import test_support
import os
import genericpath
class AllCommonTest(unittest.TestCase):
def assertIs(self, a, b):
self.assert_(a is b)
def test_commonprefix(self):
self.assertEqual(
genericpath.commonprefix([]),
""
)
self.assertEqual(
genericpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
"/home/swen"
)
self.assertEqual(
genericpath.commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
"/home/swen/"
)
self.assertEqual(
genericpath.commonprefix(["/home/swen/spam", "/home/swen/spam"]),
"/home/swen/spam"
)
def test_getsize(self):
f = open(test_support.TESTFN, "wb")
try:
f.write("foo")
f.close()
self.assertEqual(genericpath.getsize(test_support.TESTFN), 3)
finally:
if not f.closed:
f.close()
os.remove(test_support.TESTFN)
def test_time(self):
f = open(test_support.TESTFN, "wb")
try:
f.write("foo")
f.close()
f = open(test_support.TESTFN, "ab")
f.write("bar")
f.close()
f = open(test_support.TESTFN, "rb")
d = f.read()
f.close()
self.assertEqual(d, "foobar")
self.assert_(
genericpath.getctime(test_support.TESTFN) <=
genericpath.getmtime(test_support.TESTFN)
)
finally:
if not f.closed:
f.close()
os.remove(test_support.TESTFN)
def test_exists(self):
self.assertIs(genericpath.exists(test_support.TESTFN), False)
f = open(test_support.TESTFN, "wb")
try:
f.write("foo")
f.close()
self.assertIs(genericpath.exists(test_support.TESTFN), True)
finally:
if not f.close():
f.close()
try:
os.remove(test_support.TESTFN)
except os.error:
pass
self.assertRaises(TypeError, genericpath.exists)
def test_isdir(self):
self.assertIs(genericpath.isdir(test_support.TESTFN), False)
f = open(test_support.TESTFN, "wb")
try:
f.write("foo")
f.close()
self.assertIs(genericpath.isdir(test_support.TESTFN), False)
os.remove(test_support.TESTFN)
os.mkdir(test_support.TESTFN)
self.assertIs(genericpath.isdir(test_support.TESTFN), True)
os.rmdir(test_support.TESTFN)
finally:
if not f.close():
f.close()
try:
os.remove(test_support.TESTFN)
except os.error:
pass
try:
os.rmdir(test_support.TESTFN)
except os.error:
pass
self.assertRaises(TypeError, genericpath.isdir)
def test_isfile(self):
self.assertIs(genericpath.isfile(test_support.TESTFN), False)
f = open(test_support.TESTFN, "wb")
try:
f.write("foo")
f.close()
self.assertIs(genericpath.isfile(test_support.TESTFN), True)
os.remove(test_support.TESTFN)
os.mkdir(test_support.TESTFN)
self.assertIs(genericpath.isfile(test_support.TESTFN), False)
os.rmdir(test_support.TESTFN)
finally:
if not f.close():
f.close()
try:
os.remove(test_support.TESTFN)
except os.error:
pass
try:
os.rmdir(test_support.TESTFN)
except os.error:
pass
self.assertRaises(TypeError, genericpath.isdir)
def test_samefile(self):
f = open(test_support.TESTFN + "1", "wb")
try:
f.write("foo")
f.close()
self.assertIs(
genericpath.samefile(
test_support.TESTFN + "1",
test_support.TESTFN + "1"
),
True
)
# If we don't have links, assume that os.stat doesn't return resonable
# inode information and thus, that samefile() doesn't work
if hasattr(os, "symlink"):
os.symlink(
test_support.TESTFN + "1",
test_support.TESTFN + "2"
)
self.assertIs(
genericpath.samefile(
test_support.TESTFN + "1",
test_support.TESTFN + "2"
),
True
)
os.remove(test_support.TESTFN + "2")
f = open(test_support.TESTFN + "2", "wb")
f.write("bar")
f.close()
self.assertIs(
genericpath.samefile(
test_support.TESTFN + "1",
test_support.TESTFN + "2"
),
False
)
finally:
if not f.close():
f.close()
try:
os.remove(test_support.TESTFN + "1")
except os.error:
pass
try:
os.remove(test_support.TESTFN + "2")
except os.error:
pass
self.assertRaises(TypeError, genericpath.samefile)
def test_main():
test_support.run_unittest(AllCommonTest)
if __name__=="__main__":
test_main()