/usr/share/pyshared/unipath/path.py is in python-unipath 0.2.1+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | """unipath.py - A two-class approach to file/directory operations in Python.
Full usage, documentation, changelog, and history are at
http://sluggo.scrapping.cc/python/unipath/
(c) 2007 by Mike Orr (and others listed in "History" section of doc page).
Permission is granted to redistribute, modify, and include in commercial and
noncommercial products under the terms of the Python license (i.e., the "Python
Software Foundation License version 2" at
http://www.python.org/download/releases/2.5/license/).
"""
import errno
import fnmatch
import glob
import os
import shutil
import stat
import sys
import time
import warnings
from unipath.abstractpath import AbstractPath
from unipath.errors import RecursionError
__all__ = ["Path"]
#warnings.simplefilter("ignore", DebugWarning, append=1)
def flatten(iterable):
"""Yield each element of 'iterable', recursively interpolating
lists and tuples. Examples:
[1, [2, 3], 4] => iter([1, 2, 3, 4])
[1, (2, 3, [4]), 5) => iter([1, 2, 3, 4, 5])
"""
for elm in iterable:
if isinstance(elm, (list, tuple)):
for relm in flatten(elm):
yield relm
else:
yield elm
class Path(AbstractPath):
##### CURRENT DIRECTORY ####
@classmethod
def cwd(class_):
""" Return the current working directory as a path object. """
return class_(os.getcwd())
def chdir(self):
os.chdir(self)
#### CALCULATING PATHS ####
def absolute(self):
"""Return the absolute Path, prefixing the current directory if
necessary.
"""
return self.__class__(os.path.abspath(self))
def relative(self):
"""Return a relative path to self from the current working directory.
"""
return self.__class__.cwd().rel_path_to(self)
def rel_path_to(self, dst):
""" Return a relative path from self to dst.
This prefixes as many pardirs (``..``) as necessary to reach a common
ancestor. If there's no common ancestor (e.g., they're are on
different Windows drives), the path will be absolute.
"""
origin = self.__class__(self).absolute()
if not origin.isdir():
origin = origin.parent
dest = self.__class__(dst).absolute()
orig_list = origin.norm_case().components()
# Don't normcase dest! We want to preserve the case.
dest_list = dest.components()
if orig_list[0] != os.path.normcase(dest_list[0]):
# Can't get here from there.
return self.__class__(dest)
# Find the location where the two paths start to differ.
i = 0
for start_seg, dest_seg in zip(orig_list, dest_list):
if start_seg != os.path.normcase(dest_seg):
break
i += 1
# Now i is the point where the two paths diverge.
# Need a certain number of "os.pardir"s to work up
# from the origin to the point of divergence.
segments = [os.pardir] * (len(orig_list) - i)
# Need to add the diverging part of dest_list.
segments += dest_list[i:]
if len(segments) == 0:
# If they happen to be identical, use os.curdir.
return self.__class__(os.curdir)
else:
newpath = os.path.join(*segments)
return self.__class__(newpath)
def resolve(self):
"""Return an equivalent Path that does not contain symbolic links."""
return self.__class__(os.path.realpath(self))
#### LISTING DIRECTORIES ####
def listdir(self, pattern=None, filter=None, names_only=False):
if names_only and filter is not None:
raise TypeError("filter not allowed if 'names_only' is true")
empty_path = self == ""
if empty_path:
names = os.listdir(os.path.curdir)
else:
names = os.listdir(self)
if pattern is not None:
names = fnmatch.filter(names, pattern)
names.sort()
if names_only:
return names
ret = [self.child(x) for x in names]
if filter is not None:
ret = [x for x in ret if filter(x)]
return ret
def walk(self, pattern=None, filter=None, top_down=True):
return self._walk(pattern, filter, top_down, set())
def _walk(self, pattern, filter, top_down, seen):
if not self.isdir():
raise RecursionError("not a directory: %s" % self)
real_dir = self.resolve()
if real_dir in seen:
return # We've already recursed this directory.
seen.add(real_dir)
for child in self.listdir(pattern):
is_dir = child.isdir()
if is_dir and not top_down:
for grandkid in child._walk(pattern, filter, top_down, seen):
yield grandkid
if filter is None or filter(child):
yield child
if is_dir and top_down:
for grandkid in child._walk(pattern, filter, top_down, seen):
yield grandkid
#### STAT ATTRIBUTES ####
exists = os.path.exists
lexists = os.path.lexists
isfile = os.path.isfile
isdir = os.path.isdir
islink = os.path.islink
ismount = os.path.ismount
atime = os.path.getatime
ctime = os.path.getctime
mtime = os.path.getmtime
size = os.path.getsize
if hasattr(os.path, 'samefile'):
same_file = os.path.samefile
# For some reason these functions have to be wrapped in methods.
def stat(self):
return os.stat(self)
def lstat(self):
return os.lstat(self)
if hasattr(os, 'statvfs'):
def statvfs(self):
return os.statvfs(self)
def chmod(self, mode):
os.chmod(self, mode)
if hasattr(os, 'chown'):
def chown(self, uid, gid):
os.chown(self, uid, gid)
def set_times(self, mtime=None, atime=None):
"""Set a path's modification and access times.
Times must be in ticks as returned by ``time.time()``.
If 'mtime' is None, use the current time.
If 'atime' is None, use 'mtime'.
Creates an empty file if the path does not exists.
On some platforms (Windows), the path must not be a directory.
"""
if not self.exists():
fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
os.close(fd)
if mtime is None:
mtime = time.time()
if atime is None:
atime = mtime
times = atime, mtime
os.utime(self, times)
#### CREATING, REMOVING, AND RENAMING ####
def mkdir(self, parents=False, mode=0777):
if self.exists():
return
if parents:
os.makedirs(self, mode)
else:
os.mkdir(self, mode)
def rmdir(self, parents=False):
if not self.exists():
return
if parents:
os.removedirs(self)
else:
os.rmdir(self)
def remove(self):
if self.exists():
os.remove(self)
def rename(self, new, parents=False):
if parents:
os.renames(self, new)
else:
os.rename(self, new)
#### SYMBOLIC AND HARD LINKS ####
if hasattr(os, 'link'):
def hardlink(self, newpath):
"""Create a hard link at 'newpath' pointing to self. """
os.link(self, newpath)
if hasattr(os, 'symlink'):
def write_link(self, link_content):
"""Create a symbolic link at self pointing to 'link_content'.
This is the same as .symlink but with the args reversed.
"""
os.symlink(link_content, self)
def make_relative_link_to(self, dest):
"""Make a relative symbolic link from self to dest.
Same as self.write_link(self.rel_path_to(dest))
"""
link_content = self.rel_path_to(dest)
self.write_link(link_content)
if hasattr(os, 'readlink'):
def read_link(self, absolute=False):
p = self.__class__(os.readlink(self))
if absolute and not p.isabsolute():
p = self.__class__(self.parent, p)
return p
#### HIGH-LEVEL OPERATIONS ####
def copy(self, dst, times=False, perms=False):
"""Copy the file, optionally copying the permission bits (mode) and
last access/modify time. If the destination file exists, it will be
replaced. Raises OSError if the destination is a directory. If the
platform does not have the ability to set the permission or times,
ignore it.
This is shutil.copyfile plus bits of shutil.copymode and
shutil.copystat's implementation.
shutil.copy and shutil.copy2 are not supported but are easy to do.
"""
shutil.copyfile(self, dst)
if times or perms:
self.copy_stat(dst, times, perms)
def copy_stat(self, dst, times=True, perms=True):
st = os.stat(self)
if hasattr(os, 'utime'):
os.utime(dst, (st.st_atime, st.st_mtime))
if hasattr(os, 'chmod'):
m = stat.S_IMODE(st.st_mode)
os.chmod(dst, m)
def copy_tree(dst, perserve_symlinks=False, times=False, perms=False):
raise NotImplementedError()
if hasattr(shutil, 'move'):
move = shutil.move
def needs_update(self, others):
if not self.exists():
return True
control = self.mtime()
for p in flatten(others):
if p.isdir():
for child in p.walk(filter=FILES):
if child.mtime() > control:
return True
elif p.mtime() > control:
return True
return False
def read_file(self, mode="rU"):
f = open(self, mode)
content = f.read()
f.close()
return content
def rmtree(self, parents=False):
"""Delete self recursively, whether it's a file or directory.
directory, remove it recursively (same as shutil.rmtree). If it
doesn't exist, do nothing.
If you're looking for a 'rmtree' method, this is what you want.
"""
if self.isfile():
os.remove(self)
elif self.isdir():
shutil.rmtree(self)
if not parents:
return
p = self.parent
while p:
try:
os.rmdir(p)
except os.error:
break
p = p.parent
def write_file(self, content, mode="w"):
f = open(self, mode)
f.write(content)
f.close()
|