move localpath implementation to a single file, simplify unix/posix difference and fix a bit

--HG--
branch : trunk
This commit is contained in:
holger krekel 2009-08-20 17:37:06 +02:00
parent 079a2327ec
commit 561fdca3a2
13 changed files with 378 additions and 470 deletions

4
bin-for-dist/all-plat.sh Normal file → Executable file
View File

@ -1,6 +1,6 @@
py.test --dist=each $* \ py.test --dist=each $* \
--tx 'popen//python=python2.6' \
--tx 'ssh=noco//python=/usr/local/bin/python2.4//chdir=/tmp/pytest-python2.4' \
--tx 'socket=192.168.1.106:8888' --tx 'socket=192.168.1.106:8888'
#--tx 'popen//python=python2.6' \
#--tx 'ssh=noco//python=/usr/local/bin/python2.4//chdir=/tmp/pytest-python2.4' \

View File

@ -1,3 +1,8 @@
Changes between 1.0.x and 'trunk'
=====================================
* simplified internal localpath implementation
Changes between 1.0.0 and 1.0.1 Changes between 1.0.0 and 1.0.1
===================================== =====================================

View File

@ -106,7 +106,7 @@ initpkg(__name__,
'path.__doc__' : ('./path/__init__.py', '__doc__'), 'path.__doc__' : ('./path/__init__.py', '__doc__'),
'path.svnwc' : ('./path/svn/wccommand.py', 'SvnWCCommandPath'), 'path.svnwc' : ('./path/svn/wccommand.py', 'SvnWCCommandPath'),
'path.svnurl' : ('./path/svn/urlcommand.py', 'SvnCommandPath'), 'path.svnurl' : ('./path/svn/urlcommand.py', 'SvnCommandPath'),
'path.local' : ('./path/local/local.py', 'LocalPath'), 'path.local' : ('./path/local.py', 'LocalPath'),
'path.SvnAuth' : ('./path/svn/svncommon.py', 'SvnAuth'), 'path.SvnAuth' : ('./path/svn/svncommon.py', 'SvnAuth'),
# some nice slightly magic APIs # some nice slightly magic APIs

View File

@ -1,9 +1,5 @@
""" """
specialized local path implementation. local path implementation.
This Path implementation offers some methods like chmod(), owner()
and so on that may only make sense on unix.
""" """
from __future__ import generators from __future__ import generators
import sys, os, stat, re, atexit import sys, os, stat, re, atexit
@ -12,17 +8,93 @@ from py.__.path import common
iswin32 = sys.platform == "win32" iswin32 = sys.platform == "win32"
if iswin32: class Stat(object):
from py.__.path.local.win import WinMixin as PlatformMixin pformat = "%s = property(lambda x: getattr(x._osstatresult, 'st_%s'))"
else:
from py.__.path.local.posix import PosixMixin as PlatformMixin
class LocalPath(common.FSPathBase, PlatformMixin): for name in ('atime blksize blocks ctime dev gid '
""" Local path implementation offering access/modification 'ino mode mtime nlink rdev size uid'.split()):
methods similar to os.path. code = pformat.replace("%s", name)
exec code
def __init__(self, path, osstatresult):
self.path = path
self._osstatresult = osstatresult
def owner(self):
if iswin32:
raise NotImplementedError("XXX win32")
import pwd
entry = self.path._callex(pwd.getpwuid, self.uid)
return entry[0]
owner = property(owner, None, None, "owner of path")
def group(self):
""" return group name of file. """
if iswin32:
raise NotImplementedError("XXX win32")
import grp
entry = self.path._callex(grp.getgrgid, self.gid)
return entry[0]
group = property(group)
class PosixPath(common.FSPathBase):
def chown(self, user, group, rec=0):
""" change ownership to the given user and group.
user and group may be specified by a number or
by a name. if rec is True change ownership
recursively.
"""
uid = getuserid(user)
gid = getgroupid(group)
if rec:
for x in self.visit(rec=lambda x: x.check(link=0)):
if x.check(link=0):
self._callex(os.chown, str(x), uid, gid)
self._callex(os.chown, str(self), uid, gid)
def readlink(self):
""" return value of a symbolic link. """
return self._callex(os.readlink, self.strpath)
def mklinkto(self, oldname):
""" posix style hard link to another name. """
self._callex(os.link, str(oldname), str(self))
def mksymlinkto(self, value, absolute=1):
""" create a symbolic link with the given value (pointing to another name). """
if absolute:
self._callex(os.symlink, str(value), self.strpath)
else:
base = self.common(value)
# with posix local paths '/' is always a common base
relsource = self.__class__(value).relto(base)
reldest = self.relto(base)
n = reldest.count(self.sep)
target = self.sep.join(('..', )*n + (relsource, ))
self._callex(os.symlink, target, self.strpath)
def samefile(self, other):
""" return True if other refers to the same stat object as self. """
return py.std.os.path.samefile(str(self), str(other))
def getuserid(user):
import pwd
if not isinstance(user, int):
user = pwd.getpwnam(user)[2]
return user
def getgroupid(group):
import grp
if not isinstance(group, int):
group = grp.getgrnam(group)[2]
return group
FSBase = not iswin32 and PosixPath or common.FSPathBase
class LocalPath(FSBase):
""" object oriented interface to os.path and other local filesystem
related information.
""" """
_path_cache = {}
sep = os.sep sep = os.sep
class Checkers(common.FSCheckers): class Checkers(common.FSCheckers):
def _stat(self): def _stat(self):
@ -76,6 +148,21 @@ class LocalPath(common.FSPathBase, PlatformMixin):
def __hash__(self): def __hash__(self):
return hash(self.strpath) return hash(self.strpath)
def remove(self, rec=1):
""" remove a file or directory (or a directory tree if rec=1). """
if self.check(dir=1, link=0):
if rec:
# force remove of readonly files on windows
if iswin32:
self.chmod(0700, rec=1)
self._callex(py.std.shutil.rmtree, self.strpath)
else:
self._callex(os.rmdir, self.strpath)
else:
if iswin32:
self.chmod(0700)
self._callex(os.remove, self.strpath)
def computehash(self, hashtype="md5", chunksize=524288): def computehash(self, hashtype="md5", chunksize=524288):
""" return hexdigest of hashvalue for this file. """ """ return hexdigest of hashvalue for this file. """
hash = self._gethashinstance(hashtype) hash = self._gethashinstance(hashtype)
@ -311,14 +398,12 @@ class LocalPath(common.FSPathBase, PlatformMixin):
def stat(self): def stat(self):
""" Return an os.stat() tuple. """ """ Return an os.stat() tuple. """
stat = self._callex(os.stat, self.strpath) return Stat(self, self._callex(os.stat, self.strpath))
return self._makestat(stat)
def lstat(self): def lstat(self):
""" Return an os.lstat() tuple. """ """ Return an os.lstat() tuple. """
return self._makestat(self._callex(os.lstat, self.strpath)) return Stat(self, self._callex(os.lstat, self.strpath))
# xlocal implementation
def setmtime(self, mtime=None): def setmtime(self, mtime=None):
""" set modification time for the given path. if 'mtime' is None """ set modification time for the given path. if 'mtime' is None
(the default) then the file's mtime is set to current time. (the default) then the file's mtime is set to current time.
@ -379,6 +464,18 @@ class LocalPath(common.FSPathBase, PlatformMixin):
#print "prepending to sys.path", s #print "prepending to sys.path", s
sys.path.insert(0, s) sys.path.insert(0, s)
def chmod(self, mode, rec=0):
""" change permissions to the given mode. If mode is an
integer it directly encodes the os-specific modes.
if rec is True perform recursively.
"""
if not isinstance(mode, int):
raise TypeError("mode %r must be an integer" % (mode,))
if rec:
for x in self.visit(rec=rec):
self._callex(os.chmod, str(x), mode)
self._callex(os.chmod, str(self), mode)
def pyimport(self, modname=None, ensuresyspath=True): def pyimport(self, modname=None, ensuresyspath=True):
""" return path as an imported python module. """ return path as an imported python module.
if modname is None, look for the containing package if modname is None, look for the containing package
@ -438,7 +535,7 @@ class LocalPath(common.FSPathBase, PlatformMixin):
def _getpycodeobj(self): def _getpycodeobj(self):
""" read the path and compile it to a code object. """ """ read the path and compile it to a code object. """
dotpy = self.check(ext='.py') dotpy = self.ext == ".py"
if dotpy: if dotpy:
my_magic = py.std.imp.get_magic() my_magic = py.std.imp.get_magic()
my_timestamp = int(self.mtime()) my_timestamp = int(self.mtime())

View File

@ -1 +0,0 @@
#

View File

@ -1,25 +0,0 @@
import py
class Stat(object):
def __init__(self, path, osstatresult):
self.path = path
self._osstatresult = osstatresult
for name in ('atime blksize blocks ctime dev gid '
'ino mode mtime nlink rdev size uid'.split()):
code = """if 1:
def fget(self):
return getattr(self._osstatresult, "st_%(name)s", None)
%(name)s = property(fget)
def fget_deprecated(self):
py.std.warnings.warn("statresult.st_%(name)s is deprecated, use "
"statresult.%(name)s instead.",
DeprecationWarning, stacklevel=2)
return getattr(self._osstatresult, "st_%(name)s", None)
st_%(name)s = property(fget_deprecated)
""" % locals()
exec code
del fget
del fget_deprecated

View File

@ -1,129 +0,0 @@
"""
module to access local filesystem pathes
(mostly filename manipulations but also file operations)
"""
import os, sys, stat
import py
#__________________________________________________________
#
# Local Path Posix Mixin
#__________________________________________________________
from py.__.path.local.common import Stat
class PosixStat(Stat):
def owner(self):
entry = self.path._callex(py.std.pwd.getpwuid, self.uid)
return entry[0]
owner = property(owner, None, None, "owner of path")
def group(self):
""" return group name of file. """
entry = self.path._callex(py.std.grp.getgrgid, self.gid)
return entry[0]
group = property(group)
class PosixMixin(object):
def _makestat(self, statresult):
return PosixStat(self, statresult)
def _deprecated(self, name):
py.std.warnings.warn("'path.%s()' is deprecated, use "
"'path.stat().%s' instead." % (name,name),
DeprecationWarning, stacklevel=3)
# an instance needs to be a local path instance
def owner(self):
""" return owner name of file. """
self._deprecated('owner')
return self.stat().owner
def group(self):
""" return group name of file. """
self._deprecated('group')
return self.stat().group
def mode(self):
""" return permission mode of the path object """
self._deprecated('mode')
return self.stat().mode
def chmod(self, mode, rec=0):
""" change permissions to the given mode. If mode is an
integer it directly encodes the os-specific modes.
if rec is True perform recursively.
(xxx if mode is a string then it specifies access rights
in '/bin/chmod' style, e.g. a+r).
"""
if not isinstance(mode, int):
raise TypeError("mode %r must be an integer" % (mode,))
if rec:
for x in self.visit(rec=rec):
self._callex(os.chmod, str(x), mode)
self._callex(os.chmod, str(self), mode)
def chown(self, user, group, rec=0):
""" change ownership to the given user and group.
user and group may be specified by a number or
by a name. if rec is True change ownership
recursively.
"""
uid = getuserid(user)
gid = getgroupid(group)
if rec:
for x in self.visit(rec=lambda x: x.check(link=0)):
if x.check(link=0):
self._callex(os.chown, str(x), uid, gid)
self._callex(os.chown, str(self), uid, gid)
def readlink(self):
""" return value of a symbolic link. """
return self._callex(os.readlink, self.strpath)
def mklinkto(self, oldname):
""" posix style hard link to another name. """
self._callex(os.link, str(oldname), str(self))
def mksymlinkto(self, value, absolute=1):
""" create a symbolic link with the given value (pointing to another name). """
if absolute:
self._callex(os.symlink, str(value), self.strpath)
else:
base = self.common(value)
# with posix local paths '/' is always a common base
relsource = self.__class__(value).relto(base)
reldest = self.relto(base)
n = reldest.count(self.sep)
target = self.sep.join(('..', )*n + (relsource, ))
self._callex(os.symlink, target, self.strpath)
def remove(self, rec=1):
""" remove a file or directory (or a directory tree if rec=1). """
if self.check(dir=1, link=0):
if rec:
self._callex(py.std.shutil.rmtree, self.strpath)
else:
self._callex(os.rmdir, self.strpath)
else:
self._callex(os.remove, self.strpath)
def samefile(self, other):
""" return True if other refers to the same stat object as self. """
return py.std.os.path.samefile(str(self), str(other))
def getuserid(user):
import pwd
if isinstance(user, int):
return user
entry = pwd.getpwnam(user)
return entry[2]
def getgroupid(group):
import grp
if isinstance(group, int):
return group
entry = grp.getgrnam(group)
return entry[2]

View File

@ -1 +0,0 @@
#

View File

@ -1,190 +0,0 @@
import py
class TestPOSIXLocalPath:
disabled = py.std.sys.platform == 'win32'
def setup_class(cls):
cls.root = py.test.ensuretemp(cls.__name__)
def setup_method(self, method):
name = method.im_func.func_name
self.tmpdir = self.root.ensure(name, dir=1)
def test_samefile(self):
assert self.tmpdir.samefile(self.tmpdir)
p = self.tmpdir.ensure("hello")
assert p.samefile(p)
def test_hardlink(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("Hello")
nlink = filepath.stat().st_nlink
linkpath.mklinkto(filepath)
assert filepath.stat().st_nlink == nlink + 1
def test_symlink_are_identical(self):
tmpdir = self.tmpdir
filepath = tmpdir.join('file')
filepath.write("Hello")
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(filepath)
assert linkpath.readlink() == str(filepath)
def test_symlink_isfile(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("")
linkpath.mksymlinkto(filepath)
assert linkpath.check(file=1)
assert not linkpath.check(link=0, file=1)
def test_symlink_relative(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("Hello")
linkpath.mksymlinkto(filepath, absolute=False)
assert linkpath.readlink() == "file"
assert filepath.read() == linkpath.read()
def test_symlink_not_existing(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('testnotexisting')
assert not linkpath.check(link=1)
assert linkpath.check(link=0)
def test_relto_with_root(self):
y = self.root.join('x').relto(py.path.local('/'))
assert y[0] == str(self.root)[1]
def test_visit_recursive_symlink(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(tmpdir)
visitor = tmpdir.visit(None, lambda x: x.check(link=0))
assert list(visitor) == [linkpath]
def test_symlink_isdir(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(tmpdir)
assert linkpath.check(dir=1)
assert not linkpath.check(link=0, dir=1)
def test_symlink_remove(self):
tmpdir = self.tmpdir.realpath()
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(linkpath) # point to itself
assert linkpath.check(link=1)
linkpath.remove()
assert not linkpath.check()
def test_realpath_file(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("")
linkpath.mksymlinkto(filepath)
realpath = linkpath.realpath()
assert realpath.basename == 'file'
def test_owner(self):
from pwd import getpwuid
from grp import getgrgid
stat = self.root.stat()
assert stat.path == self.root
uid = stat.st_uid
gid = stat.st_gid
owner = getpwuid(uid)[0]
group = getgrgid(gid)[0]
assert uid == stat.uid
assert owner == stat.owner
assert gid == stat.gid
assert group == stat.group
def test_atime(self):
import time
path = self.root.ensure('samplefile')
now = time.time()
atime1 = path.atime()
# we could wait here but timer resolution is very
# system dependent
path.read()
atime2 = path.atime()
duration = time.time() - now
assert (atime2-atime1) <= duration
def test_commondir(self):
# XXX This is here in local until we find a way to implement this
# using the subversion command line api.
p1 = self.root.join('something')
p2 = self.root.join('otherthing')
assert p1.common(p2) == self.root
assert p2.common(p1) == self.root
def test_commondir_nocommon(self):
# XXX This is here in local until we find a way to implement this
# using the subversion command line api.
p1 = self.root.join('something')
p2 = py.path.local(self.root.sep+'blabla')
assert p1.common(p2) == '/'
def test_join_to_root(self):
root = self.root.parts()[0]
assert len(str(root)) == 1
assert str(root.join('a')) == '/a'
def test_join_root_to_root_with_no_abs(self):
nroot = self.root.join('/')
assert str(self.root) == str(nroot)
assert self.root == nroot
def test_chmod_simple_int(self):
print "self.root is", self.root
mode = self.root.mode()
self.root.chmod(mode/2)
try:
assert self.root.mode() != mode
finally:
self.root.chmod(mode)
assert self.root.mode() == mode
def test_chmod_rec_int(self):
# XXX fragile test
print "self.root is", self.root
recfilter = lambda x: x.check(dotfile=0, link=0)
oldmodes = {}
for x in self.root.visit(rec=recfilter):
oldmodes[x] = x.mode()
self.root.chmod(0772, rec=recfilter)
try:
for x in self.root.visit(rec=recfilter):
assert x.mode() & 0777 == 0772
finally:
for x,y in oldmodes.items():
x.chmod(y)
def test_chown_identity(self):
owner = self.root.owner()
group = self.root.group()
self.root.chown(owner, group)
def test_chown_dangling_link(self):
owner = self.root.owner()
group = self.root.group()
x = self.root.join('hello')
x.mksymlinkto('qlwkejqwlek')
try:
self.root.chown(owner, group, rec=1)
finally:
x.remove(rec=0)
def test_chown_identity_rec_mayfail(self):
owner = self.root.owner()
group = self.root.group()
self.root.chown(owner, group)

View File

@ -1,56 +0,0 @@
import py
class TestWINLocalPath:
#root = local(TestLocalPath.root)
disabled = py.std.sys.platform != 'win32'
def setup_class(cls):
cls.root = py.test.ensuretemp(cls.__name__)
def setup_method(self, method):
name = method.im_func.func_name
self.tmpdir = self.root.ensure(name, dir=1)
def test_chmod_simple_int(self):
print "self.root is", self.root
mode = self.root.stat().st_mode
# Ensure that we actually change the mode to something different.
self.root.chmod(mode == 0 and 1 or 0)
try:
print self.root.stat().st_mode
print mode
assert self.root.stat().st_mode != mode
finally:
self.root.chmod(mode)
assert self.root.stat().st_mode == mode
def test_path_comparison_lowercase_mixed(self):
t1 = self.root.join("a_path")
t2 = self.root.join("A_path")
assert t1 == t1
assert t1 == t2
def test_relto_with_mixed_case(self):
t1 = self.root.join("a_path", "fiLe")
t2 = self.root.join("A_path")
assert t1.relto(t2) == "fiLe"
def test_allow_unix_style_paths(self):
t1 = self.root.join('a_path')
assert t1 == str(self.root) + '\\a_path'
t1 = self.root.join('a_path/')
assert t1 == str(self.root) + '\\a_path'
t1 = self.root.join('dir/a_path')
assert t1 == str(self.root) + '\\dir\\a_path'
def test_sysfind_in_currentdir(self):
cmd = py.path.local.sysfind('cmd')
root = cmd.new(dirname='', basename='') # c:\ in most installations
old = root.chdir()
try:
x = py.path.local.sysfind(cmd.relto(root))
assert x.check(file=1)
finally:
old.chdir()

View File

@ -1,41 +0,0 @@
"""
module for win-specific local path stuff
(implementor needed :-)
"""
import os
import py
from py.__.path.local.common import Stat
class WinMixin:
def _makestat(self, statresult):
return Stat(self, statresult)
def chmod(self, mode, rec=0):
""" change permissions to the given mode. If mode is an
integer it directly encodes the os-specific modes.
if rec is True perform recursively.
(xxx if mode is a string then it specifies access rights
in '/bin/chmod' style, e.g. a+r).
"""
if not isinstance(mode, int):
raise TypeError("mode %r must be an integer" % (mode,))
if rec:
for x in self.visit(rec=rec):
self._callex(os.chmod, str(x), mode)
self._callex(os.chmod, str(self), mode)
def remove(self, rec=1):
""" remove a file or directory (or a directory tree if rec=1). """
if self.check(dir=1, link=0):
if rec:
# force remove of readonly files on windows
self.chmod(0700, rec=1)
self._callex(py.std.shutil.rmtree, self.strpath)
else:
self._callex(os.rmdir, self.strpath)
else:
self.chmod(0700)
self._callex(os.remove, self.strpath)

View File

@ -94,8 +94,6 @@ class CommonFSTests(common.CommonPathTests):
assert not self.root.join("sampledir").check(file=1) assert not self.root.join("sampledir").check(file=1)
assert self.root.join("sampledir").check(file=0) assert self.root.join("sampledir").check(file=0)
#def test_fnmatch_dir(self):
def test_non_existent(self): def test_non_existent(self):
assert self.root.join("sampledir.nothere").check(dir=0) assert self.root.join("sampledir.nothere").check(dir=0)
assert self.root.join("sampledir.nothere").check(file=0) assert self.root.join("sampledir.nothere").check(file=0)
@ -205,8 +203,12 @@ class CommonFSTests(common.CommonPathTests):
p = self.root.join('samplefile') p = self.root.join('samplefile')
newp = p.dirpath('moved_samplefile') newp = p.dirpath('moved_samplefile')
p.move(newp) p.move(newp)
assert newp.check(file=1) try:
assert not p.check() assert newp.check(file=1)
assert not p.check()
finally:
newp.move(p)
assert p.check()
def test_move_directory(self): def test_move_directory(self):
source = self.root.join('sampledir') source = self.root.join('sampledir')

View File

@ -12,8 +12,10 @@ class LocalSetup:
def setup_method(self, method): def setup_method(self, method):
self.tmpdir = self.root.mkdir(method.__name__) self.tmpdir = self.root.mkdir(method.__name__)
class TestLocalPath(LocalSetup, CommonFSTests): def teardown_method(self, method):
assert self.root.join("samplefile").check()
class TestLocalPath(LocalSetup, CommonFSTests):
def test_join_normpath(self): def test_join_normpath(self):
assert self.tmpdir.join(".") == self.tmpdir assert self.tmpdir.join(".") == self.tmpdir
p = self.tmpdir.join("../%s" % self.tmpdir.basename) p = self.tmpdir.join("../%s" % self.tmpdir.basename)
@ -347,3 +349,248 @@ def test_homedir():
homedir = py.path.local._gethomedir() homedir = py.path.local._gethomedir()
assert homedir.check(dir=1) assert homedir.check(dir=1)
class TestWINLocalPath:
#root = local(TestLocalPath.root)
disabled = py.std.sys.platform != 'win32'
def setup_class(cls):
cls.root = py.test.ensuretemp(cls.__name__)
def setup_method(self, method):
name = method.im_func.func_name
self.tmpdir = self.root.ensure(name, dir=1)
def test_owner_group_not_implemented(self):
py.test.raises(NotImplementedError, "self.root.stat().owner")
py.test.raises(NotImplementedError, "self.root.stat().group")
def test_chmod_simple_int(self):
print "self.root is", self.root
mode = self.root.stat().mode
# Ensure that we actually change the mode to something different.
self.root.chmod(mode == 0 and 1 or 0)
try:
print self.root.stat().mode
print mode
assert self.root.stat().mode != mode
finally:
self.root.chmod(mode)
assert self.root.stat().mode == mode
def test_path_comparison_lowercase_mixed(self):
t1 = self.root.join("a_path")
t2 = self.root.join("A_path")
assert t1 == t1
assert t1 == t2
def test_relto_with_mixed_case(self):
t1 = self.root.join("a_path", "fiLe")
t2 = self.root.join("A_path")
assert t1.relto(t2) == "fiLe"
def test_allow_unix_style_paths(self):
t1 = self.root.join('a_path')
assert t1 == str(self.root) + '\\a_path'
t1 = self.root.join('a_path/')
assert t1 == str(self.root) + '\\a_path'
t1 = self.root.join('dir/a_path')
assert t1 == str(self.root) + '\\dir\\a_path'
def test_sysfind_in_currentdir(self):
cmd = py.path.local.sysfind('cmd')
root = cmd.new(dirname='', basename='') # c:\ in most installations
old = root.chdir()
try:
x = py.path.local.sysfind(cmd.relto(root))
assert x.check(file=1)
finally:
old.chdir()
class TestPOSIXLocalPath:
disabled = py.std.sys.platform == 'win32'
def setup_class(cls):
cls.root = py.test.ensuretemp(cls.__name__)
def setup_method(self, method):
name = method.im_func.func_name
self.tmpdir = self.root.ensure(name, dir=1)
def test_samefile(self):
assert self.tmpdir.samefile(self.tmpdir)
p = self.tmpdir.ensure("hello")
assert p.samefile(p)
def test_hardlink(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("Hello")
nlink = filepath.stat().nlink
linkpath.mklinkto(filepath)
assert filepath.stat().nlink == nlink + 1
def test_symlink_are_identical(self):
tmpdir = self.tmpdir
filepath = tmpdir.join('file')
filepath.write("Hello")
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(filepath)
assert linkpath.readlink() == str(filepath)
def test_symlink_isfile(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("")
linkpath.mksymlinkto(filepath)
assert linkpath.check(file=1)
assert not linkpath.check(link=0, file=1)
def test_symlink_relative(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("Hello")
linkpath.mksymlinkto(filepath, absolute=False)
assert linkpath.readlink() == "file"
assert filepath.read() == linkpath.read()
def test_symlink_not_existing(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('testnotexisting')
assert not linkpath.check(link=1)
assert linkpath.check(link=0)
def test_relto_with_root(self):
y = self.root.join('x').relto(py.path.local('/'))
assert y[0] == str(self.root)[1]
def test_visit_recursive_symlink(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(tmpdir)
visitor = tmpdir.visit(None, lambda x: x.check(link=0))
assert list(visitor) == [linkpath]
def test_symlink_isdir(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(tmpdir)
assert linkpath.check(dir=1)
assert not linkpath.check(link=0, dir=1)
def test_symlink_remove(self):
tmpdir = self.tmpdir.realpath()
linkpath = tmpdir.join('test')
linkpath.mksymlinkto(linkpath) # point to itself
assert linkpath.check(link=1)
linkpath.remove()
assert not linkpath.check()
def test_realpath_file(self):
tmpdir = self.tmpdir
linkpath = tmpdir.join('test')
filepath = tmpdir.join('file')
filepath.write("")
linkpath.mksymlinkto(filepath)
realpath = linkpath.realpath()
assert realpath.basename == 'file'
def test_owner(self):
from pwd import getpwuid
from grp import getgrgid
stat = self.root.stat()
assert stat.path == self.root
uid = stat.uid
gid = stat.gid
owner = getpwuid(uid)[0]
group = getgrgid(gid)[0]
assert uid == stat.uid
assert owner == stat.owner
assert gid == stat.gid
assert group == stat.group
def test_atime(self):
import time
path = self.root.ensure('samplefile')
now = time.time()
atime1 = path.atime()
# we could wait here but timer resolution is very
# system dependent
path.read()
atime2 = path.atime()
duration = time.time() - now
assert (atime2-atime1) <= duration
def test_commondir(self):
# XXX This is here in local until we find a way to implement this
# using the subversion command line api.
p1 = self.root.join('something')
p2 = self.root.join('otherthing')
assert p1.common(p2) == self.root
assert p2.common(p1) == self.root
def test_commondir_nocommon(self):
# XXX This is here in local until we find a way to implement this
# using the subversion command line api.
p1 = self.root.join('something')
p2 = py.path.local(self.root.sep+'blabla')
assert p1.common(p2) == '/'
def test_join_to_root(self):
root = self.root.parts()[0]
assert len(str(root)) == 1
assert str(root.join('a')) == '/a'
def test_join_root_to_root_with_no_abs(self):
nroot = self.root.join('/')
assert str(self.root) == str(nroot)
assert self.root == nroot
def test_chmod_simple_int(self):
print "self.root is", self.root
mode = self.root.stat().mode
self.root.chmod(mode/2)
try:
assert self.root.stat().mode != mode
finally:
self.root.chmod(mode)
assert self.root.stat().mode == mode
def test_chmod_rec_int(self):
# XXX fragile test
print "self.root is", self.root
recfilter = lambda x: x.check(dotfile=0, link=0)
oldmodes = {}
for x in self.root.visit(rec=recfilter):
oldmodes[x] = x.stat().mode
self.root.chmod(0772, rec=recfilter)
try:
for x in self.root.visit(rec=recfilter):
assert x.stat().mode & 0777 == 0772
finally:
for x,y in oldmodes.items():
x.chmod(y)
def test_chown_identity(self):
owner = self.root.stat().owner
group = self.root.stat().group
self.root.chown(owner, group)
def test_chown_dangling_link(self):
owner = self.root.stat().owner
group = self.root.stat().group
x = self.root.join('hello')
x.mksymlinkto('qlwkejqwlek')
try:
self.root.chown(owner, group, rec=1)
finally:
x.remove(rec=0)
def test_chown_identity_rec_mayfail(self):
owner = self.root.stat().owner
group = self.root.stat().group
self.root.chown(owner, group)