PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/py/_path/local.py

https://bitbucket.org/dac_io/pypy
Python | 785 lines | 746 code | 14 blank | 25 comment | 13 complexity | d5988498977e0f1b8ce929cd450713cb MD5 | raw file
  1. """
  2. local path implementation.
  3. """
  4. import sys, os, stat, re, atexit
  5. import py
  6. from py._path import common
  7. iswin32 = sys.platform == "win32" or (getattr(os, '_name', False) == 'nt')
  8. class Stat(object):
  9. def __getattr__(self, name):
  10. return getattr(self._osstatresult, "st_" + name)
  11. def __init__(self, path, osstatresult):
  12. self.path = path
  13. self._osstatresult = osstatresult
  14. def owner(self):
  15. if iswin32:
  16. raise NotImplementedError("XXX win32")
  17. import pwd
  18. entry = py.error.checked_call(pwd.getpwuid, self.uid)
  19. return entry[0]
  20. owner = property(owner, None, None, "owner of path")
  21. def group(self):
  22. """ return group name of file. """
  23. if iswin32:
  24. raise NotImplementedError("XXX win32")
  25. import grp
  26. entry = py.error.checked_call(grp.getgrgid, self.gid)
  27. return entry[0]
  28. group = property(group)
  29. class PosixPath(common.PathBase):
  30. def chown(self, user, group, rec=0):
  31. """ change ownership to the given user and group.
  32. user and group may be specified by a number or
  33. by a name. if rec is True change ownership
  34. recursively.
  35. """
  36. uid = getuserid(user)
  37. gid = getgroupid(group)
  38. if rec:
  39. for x in self.visit(rec=lambda x: x.check(link=0)):
  40. if x.check(link=0):
  41. py.error.checked_call(os.chown, str(x), uid, gid)
  42. py.error.checked_call(os.chown, str(self), uid, gid)
  43. def readlink(self):
  44. """ return value of a symbolic link. """
  45. return py.error.checked_call(os.readlink, self.strpath)
  46. def mklinkto(self, oldname):
  47. """ posix style hard link to another name. """
  48. py.error.checked_call(os.link, str(oldname), str(self))
  49. def mksymlinkto(self, value, absolute=1):
  50. """ create a symbolic link with the given value (pointing to another name). """
  51. if absolute:
  52. py.error.checked_call(os.symlink, str(value), self.strpath)
  53. else:
  54. base = self.common(value)
  55. # with posix local paths '/' is always a common base
  56. relsource = self.__class__(value).relto(base)
  57. reldest = self.relto(base)
  58. n = reldest.count(self.sep)
  59. target = self.sep.join(('..', )*n + (relsource, ))
  60. py.error.checked_call(os.symlink, target, self.strpath)
  61. def getuserid(user):
  62. import pwd
  63. if not isinstance(user, int):
  64. user = pwd.getpwnam(user)[2]
  65. return user
  66. def getgroupid(group):
  67. import grp
  68. if not isinstance(group, int):
  69. group = grp.getgrnam(group)[2]
  70. return group
  71. FSBase = not iswin32 and PosixPath or common.PathBase
  72. class LocalPath(FSBase):
  73. """ object oriented interface to os.path and other local filesystem
  74. related information.
  75. """
  76. class ImportMismatchError(ImportError):
  77. """ raised on pyimport() if there is a mismatch of __file__'s"""
  78. sep = os.sep
  79. class Checkers(common.Checkers):
  80. def _stat(self):
  81. try:
  82. return self._statcache
  83. except AttributeError:
  84. try:
  85. self._statcache = self.path.stat()
  86. except py.error.ELOOP:
  87. self._statcache = self.path.lstat()
  88. return self._statcache
  89. def dir(self):
  90. return stat.S_ISDIR(self._stat().mode)
  91. def file(self):
  92. return stat.S_ISREG(self._stat().mode)
  93. def exists(self):
  94. return self._stat()
  95. def link(self):
  96. st = self.path.lstat()
  97. return stat.S_ISLNK(st.mode)
  98. def __new__(cls, path=None):
  99. """ Initialize and return a local Path instance.
  100. Path can be relative to the current directory.
  101. If it is None then the current working directory is taken.
  102. Note that Path instances always carry an absolute path.
  103. Note also that passing in a local path object will simply return
  104. the exact same path object. Use new() to get a new copy.
  105. """
  106. if isinstance(path, common.PathBase):
  107. if path.__class__ == cls:
  108. return path
  109. path = path.strpath
  110. # initialize the path
  111. self = object.__new__(cls)
  112. if not path:
  113. self.strpath = os.getcwd()
  114. elif isinstance(path, py.builtin._basestring):
  115. self.strpath = os.path.abspath(os.path.normpath(str(path)))
  116. else:
  117. raise ValueError("can only pass None, Path instances "
  118. "or non-empty strings to LocalPath")
  119. assert isinstance(self.strpath, str)
  120. return self
  121. def __hash__(self):
  122. return hash(self.strpath)
  123. def __eq__(self, other):
  124. s1 = str(self)
  125. s2 = str(other)
  126. if iswin32:
  127. s1 = s1.lower()
  128. s2 = s2.lower()
  129. return s1 == s2
  130. def __ne__(self, other):
  131. return not (self == other)
  132. def __lt__(self, other):
  133. return str(self) < str(other)
  134. def samefile(self, other):
  135. """ return True if 'other' references the same file as 'self'.
  136. """
  137. if not isinstance(other, py.path.local):
  138. other = os.path.abspath(str(other))
  139. if self == other:
  140. return True
  141. if iswin32:
  142. return False # ther is no samefile
  143. return py.error.checked_call(
  144. os.path.samefile, str(self), str(other))
  145. def remove(self, rec=1, ignore_errors=False):
  146. """ remove a file or directory (or a directory tree if rec=1).
  147. if ignore_errors is True, errors while removing directories will
  148. be ignored.
  149. """
  150. if self.check(dir=1, link=0):
  151. if rec:
  152. # force remove of readonly files on windows
  153. if iswin32:
  154. self.chmod(448, rec=1) # octcal 0700
  155. py.error.checked_call(py.std.shutil.rmtree, self.strpath,
  156. ignore_errors=ignore_errors)
  157. else:
  158. py.error.checked_call(os.rmdir, self.strpath)
  159. else:
  160. if iswin32:
  161. self.chmod(448) # octcal 0700
  162. py.error.checked_call(os.remove, self.strpath)
  163. def computehash(self, hashtype="md5", chunksize=524288):
  164. """ return hexdigest of hashvalue for this file. """
  165. try:
  166. try:
  167. import hashlib as mod
  168. except ImportError:
  169. if hashtype == "sha1":
  170. hashtype = "sha"
  171. mod = __import__(hashtype)
  172. hash = getattr(mod, hashtype)()
  173. except (AttributeError, ImportError):
  174. raise ValueError("Don't know how to compute %r hash" %(hashtype,))
  175. f = self.open('rb')
  176. try:
  177. while 1:
  178. buf = f.read(chunksize)
  179. if not buf:
  180. return hash.hexdigest()
  181. hash.update(buf)
  182. finally:
  183. f.close()
  184. def new(self, **kw):
  185. """ create a modified version of this path.
  186. the following keyword arguments modify various path parts::
  187. a:/some/path/to/a/file.ext
  188. xx drive
  189. xxxxxxxxxxxxxxxxx dirname
  190. xxxxxxxx basename
  191. xxxx purebasename
  192. xxx ext
  193. """
  194. obj = object.__new__(self.__class__)
  195. drive, dirname, basename, purebasename,ext = self._getbyspec(
  196. "drive,dirname,basename,purebasename,ext")
  197. if 'basename' in kw:
  198. if 'purebasename' in kw or 'ext' in kw:
  199. raise ValueError("invalid specification %r" % kw)
  200. else:
  201. pb = kw.setdefault('purebasename', purebasename)
  202. try:
  203. ext = kw['ext']
  204. except KeyError:
  205. pass
  206. else:
  207. if ext and not ext.startswith('.'):
  208. ext = '.' + ext
  209. kw['basename'] = pb + ext
  210. if ('dirname' in kw and not kw['dirname']):
  211. kw['dirname'] = drive
  212. else:
  213. kw.setdefault('dirname', dirname)
  214. kw.setdefault('sep', self.sep)
  215. obj.strpath = os.path.normpath(
  216. "%(dirname)s%(sep)s%(basename)s" % kw)
  217. return obj
  218. def _getbyspec(self, spec):
  219. """ see new for what 'spec' can be. """
  220. res = []
  221. parts = self.strpath.split(self.sep)
  222. args = filter(None, spec.split(',') )
  223. append = res.append
  224. for name in args:
  225. if name == 'drive':
  226. append(parts[0])
  227. elif name == 'dirname':
  228. append(self.sep.join(parts[:-1]))
  229. else:
  230. basename = parts[-1]
  231. if name == 'basename':
  232. append(basename)
  233. else:
  234. i = basename.rfind('.')
  235. if i == -1:
  236. purebasename, ext = basename, ''
  237. else:
  238. purebasename, ext = basename[:i], basename[i:]
  239. if name == 'purebasename':
  240. append(purebasename)
  241. elif name == 'ext':
  242. append(ext)
  243. else:
  244. raise ValueError("invalid part specification %r" % name)
  245. return res
  246. def join(self, *args, **kwargs):
  247. """ return a new path by appending all 'args' as path
  248. components. if abs=1 is used restart from root if any
  249. of the args is an absolute path.
  250. """
  251. if not args:
  252. return self
  253. strpath = self.strpath
  254. sep = self.sep
  255. strargs = [str(x) for x in args]
  256. if kwargs.get('abs', 0):
  257. for i in range(len(strargs)-1, -1, -1):
  258. if os.path.isabs(strargs[i]):
  259. strpath = strargs[i]
  260. strargs = strargs[i+1:]
  261. break
  262. for arg in strargs:
  263. arg = arg.strip(sep)
  264. if iswin32:
  265. # allow unix style paths even on windows.
  266. arg = arg.strip('/')
  267. arg = arg.replace('/', sep)
  268. if arg:
  269. if not strpath.endswith(sep):
  270. strpath += sep
  271. strpath += arg
  272. obj = self.new()
  273. obj.strpath = os.path.normpath(strpath)
  274. return obj
  275. def open(self, mode='r'):
  276. """ return an opened file with the given mode. """
  277. return py.error.checked_call(open, self.strpath, mode)
  278. def listdir(self, fil=None, sort=None):
  279. """ list directory contents, possibly filter by the given fil func
  280. and possibly sorted.
  281. """
  282. if isinstance(fil, str):
  283. fil = common.FNMatcher(fil)
  284. res = []
  285. for name in py.error.checked_call(os.listdir, self.strpath):
  286. childurl = self.join(name)
  287. if fil is None or fil(childurl):
  288. res.append(childurl)
  289. self._sortlist(res, sort)
  290. return res
  291. def size(self):
  292. """ return size of the underlying file object """
  293. return self.stat().size
  294. def mtime(self):
  295. """ return last modification time of the path. """
  296. return self.stat().mtime
  297. def copy(self, target, archive=False):
  298. """ copy path to target."""
  299. assert not archive, "XXX archive-mode not supported"
  300. if self.check(file=1):
  301. if target.check(dir=1):
  302. target = target.join(self.basename)
  303. assert self!=target
  304. copychunked(self, target)
  305. else:
  306. def rec(p):
  307. return p.check(link=0)
  308. for x in self.visit(rec=rec):
  309. relpath = x.relto(self)
  310. newx = target.join(relpath)
  311. newx.dirpath().ensure(dir=1)
  312. if x.check(link=1):
  313. newx.mksymlinkto(x.readlink())
  314. elif x.check(file=1):
  315. copychunked(x, newx)
  316. elif x.check(dir=1):
  317. newx.ensure(dir=1)
  318. def rename(self, target):
  319. """ rename this path to target. """
  320. return py.error.checked_call(os.rename, str(self), str(target))
  321. def dump(self, obj, bin=1):
  322. """ pickle object into path location"""
  323. f = self.open('wb')
  324. try:
  325. py.error.checked_call(py.std.pickle.dump, obj, f, bin)
  326. finally:
  327. f.close()
  328. def mkdir(self, *args):
  329. """ create & return the directory joined with args. """
  330. p = self.join(*args)
  331. py.error.checked_call(os.mkdir, str(p))
  332. return p
  333. def write(self, data, mode='w'):
  334. """ write data into path. """
  335. if 'b' in mode:
  336. if not py.builtin._isbytes(data):
  337. raise ValueError("can only process bytes")
  338. else:
  339. if not py.builtin._istext(data):
  340. if not py.builtin._isbytes(data):
  341. data = str(data)
  342. else:
  343. data = py.builtin._totext(data, sys.getdefaultencoding())
  344. f = self.open(mode)
  345. try:
  346. f.write(data)
  347. finally:
  348. f.close()
  349. def _ensuredirs(self):
  350. parent = self.dirpath()
  351. if parent == self:
  352. return self
  353. if parent.check(dir=0):
  354. parent._ensuredirs()
  355. if self.check(dir=0):
  356. try:
  357. self.mkdir()
  358. except py.error.EEXIST:
  359. # race condition: file/dir created by another thread/process.
  360. # complain if it is not a dir
  361. if self.check(dir=0):
  362. raise
  363. return self
  364. def ensure(self, *args, **kwargs):
  365. """ ensure that an args-joined path exists (by default as
  366. a file). if you specify a keyword argument 'dir=True'
  367. then the path is forced to be a directory path.
  368. """
  369. p = self.join(*args)
  370. if kwargs.get('dir', 0):
  371. return p._ensuredirs()
  372. else:
  373. p.dirpath()._ensuredirs()
  374. if not p.check(file=1):
  375. p.open('w').close()
  376. return p
  377. def stat(self):
  378. """ Return an os.stat() tuple. """
  379. return Stat(self, py.error.checked_call(os.stat, self.strpath))
  380. def lstat(self):
  381. """ Return an os.lstat() tuple. """
  382. return Stat(self, py.error.checked_call(os.lstat, self.strpath))
  383. def setmtime(self, mtime=None):
  384. """ set modification time for the given path. if 'mtime' is None
  385. (the default) then the file's mtime is set to current time.
  386. Note that the resolution for 'mtime' is platform dependent.
  387. """
  388. if mtime is None:
  389. return py.error.checked_call(os.utime, self.strpath, mtime)
  390. try:
  391. return py.error.checked_call(os.utime, self.strpath, (-1, mtime))
  392. except py.error.EINVAL:
  393. return py.error.checked_call(os.utime, self.strpath, (self.atime(), mtime))
  394. def chdir(self):
  395. """ change directory to self and return old current directory """
  396. old = self.__class__()
  397. py.error.checked_call(os.chdir, self.strpath)
  398. return old
  399. def realpath(self):
  400. """ return a new path which contains no symbolic links."""
  401. return self.__class__(os.path.realpath(self.strpath))
  402. def atime(self):
  403. """ return last access time of the path. """
  404. return self.stat().atime
  405. def __repr__(self):
  406. return 'local(%r)' % self.strpath
  407. def __str__(self):
  408. """ return string representation of the Path. """
  409. return self.strpath
  410. def pypkgpath(self, pkgname=None):
  411. """ return the Python package path by looking for a
  412. pkgname. If pkgname is None look for the last
  413. directory upwards which still contains an __init__.py
  414. and whose basename is python-importable.
  415. Return None if a pkgpath can not be determined.
  416. """
  417. pkgpath = None
  418. for parent in self.parts(reverse=True):
  419. if pkgname is None:
  420. if parent.check(file=1):
  421. continue
  422. if not isimportable(parent.basename):
  423. break
  424. if parent.join('__init__.py').check():
  425. pkgpath = parent
  426. continue
  427. return pkgpath
  428. else:
  429. if parent.basename == pkgname:
  430. return parent
  431. return pkgpath
  432. def _prependsyspath(self, path):
  433. s = str(path)
  434. if s != sys.path[0]:
  435. #print "prepending to sys.path", s
  436. sys.path.insert(0, s)
  437. def chmod(self, mode, rec=0):
  438. """ change permissions to the given mode. If mode is an
  439. integer it directly encodes the os-specific modes.
  440. if rec is True perform recursively.
  441. """
  442. if not isinstance(mode, int):
  443. raise TypeError("mode %r must be an integer" % (mode,))
  444. if rec:
  445. for x in self.visit(rec=rec):
  446. py.error.checked_call(os.chmod, str(x), mode)
  447. py.error.checked_call(os.chmod, str(self), mode)
  448. def pyimport(self, modname=None, ensuresyspath=True):
  449. """ return path as an imported python module.
  450. if modname is None, look for the containing package
  451. and construct an according module name.
  452. The module will be put/looked up in sys.modules.
  453. """
  454. if not self.check():
  455. raise py.error.ENOENT(self)
  456. #print "trying to import", self
  457. pkgpath = None
  458. if modname is None:
  459. pkgpath = self.pypkgpath()
  460. if pkgpath is not None:
  461. if ensuresyspath:
  462. self._prependsyspath(pkgpath.dirpath())
  463. pkg = __import__(pkgpath.basename, None, None, [])
  464. names = self.new(ext='').relto(pkgpath.dirpath())
  465. names = names.split(self.sep)
  466. if names and names[-1] == "__init__":
  467. names.pop()
  468. modname = ".".join(names)
  469. else:
  470. # no package scope, still make it possible
  471. if ensuresyspath:
  472. self._prependsyspath(self.dirpath())
  473. modname = self.purebasename
  474. mod = __import__(modname, None, None, ['__doc__'])
  475. if self.basename == "__init__.py":
  476. return mod # we don't check anything as we might
  477. # we in a namespace package ... too icky to check
  478. modfile = mod.__file__
  479. if modfile[-4:] in ('.pyc', '.pyo'):
  480. modfile = modfile[:-1]
  481. elif modfile.endswith('$py.class'):
  482. modfile = modfile[:-9] + '.py'
  483. if modfile.endswith(os.path.sep + "__init__.py"):
  484. if self.basename != "__init__.py":
  485. modfile = modfile[:-12]
  486. try:
  487. issame = self.samefile(modfile)
  488. except py.error.ENOENT:
  489. issame = False
  490. if not issame:
  491. raise self.ImportMismatchError(modname, modfile, self)
  492. return mod
  493. else:
  494. try:
  495. return sys.modules[modname]
  496. except KeyError:
  497. # we have a custom modname, do a pseudo-import
  498. mod = py.std.types.ModuleType(modname)
  499. mod.__file__ = str(self)
  500. sys.modules[modname] = mod
  501. try:
  502. py.builtin.execfile(str(self), mod.__dict__)
  503. except:
  504. del sys.modules[modname]
  505. raise
  506. return mod
  507. def sysexec(self, *argv, **popen_opts):
  508. """ return stdout text from executing a system child process,
  509. where the 'self' path points to executable.
  510. The process is directly invoked and not through a system shell.
  511. """
  512. from subprocess import Popen, PIPE
  513. argv = map(str, argv)
  514. popen_opts['stdout'] = popen_opts['stderr'] = PIPE
  515. proc = Popen([str(self)] + list(argv), **popen_opts)
  516. stdout, stderr = proc.communicate()
  517. ret = proc.wait()
  518. if py.builtin._isbytes(stdout):
  519. stdout = py.builtin._totext(stdout, sys.getdefaultencoding())
  520. if ret != 0:
  521. if py.builtin._isbytes(stderr):
  522. stderr = py.builtin._totext(stderr, sys.getdefaultencoding())
  523. raise py.process.cmdexec.Error(ret, ret, str(self),
  524. stdout, stderr,)
  525. return stdout
  526. def sysfind(cls, name, checker=None):
  527. """ return a path object found by looking at the systems
  528. underlying PATH specification. If the checker is not None
  529. it will be invoked to filter matching paths. If a binary
  530. cannot be found, None is returned
  531. Note: This is probably not working on plain win32 systems
  532. but may work on cygwin.
  533. """
  534. if os.path.isabs(name):
  535. p = py.path.local(name)
  536. if p.check(file=1):
  537. return p
  538. else:
  539. if iswin32:
  540. paths = py.std.os.environ['Path'].split(';')
  541. if '' not in paths and '.' not in paths:
  542. paths.append('.')
  543. try:
  544. systemroot = os.environ['SYSTEMROOT']
  545. except KeyError:
  546. pass
  547. else:
  548. paths = [re.sub('%SystemRoot%', systemroot, path)
  549. for path in paths]
  550. tryadd = [''] + os.environ['PATHEXT'].split(os.pathsep)
  551. else:
  552. paths = py.std.os.environ['PATH'].split(':')
  553. tryadd = ('',)
  554. for x in paths:
  555. for addext in tryadd:
  556. p = py.path.local(x).join(name, abs=True) + addext
  557. try:
  558. if p.check(file=1):
  559. if checker:
  560. if not checker(p):
  561. continue
  562. return p
  563. except py.error.EACCES:
  564. pass
  565. return None
  566. sysfind = classmethod(sysfind)
  567. def _gethomedir(cls):
  568. try:
  569. x = os.environ['HOME']
  570. except KeyError:
  571. x = os.environ["HOMEDRIVE"] + os.environ['HOMEPATH']
  572. return cls(x)
  573. _gethomedir = classmethod(_gethomedir)
  574. #"""
  575. #special class constructors for local filesystem paths
  576. #"""
  577. def get_temproot(cls):
  578. """ return the system's temporary directory
  579. (where tempfiles are usually created in)
  580. """
  581. return py.path.local(py.std.tempfile.gettempdir())
  582. get_temproot = classmethod(get_temproot)
  583. def mkdtemp(cls, rootdir=None):
  584. """ return a Path object pointing to a fresh new temporary directory
  585. (which we created ourself).
  586. """
  587. import tempfile
  588. if rootdir is None:
  589. rootdir = cls.get_temproot()
  590. return cls(py.error.checked_call(tempfile.mkdtemp, dir=str(rootdir)))
  591. mkdtemp = classmethod(mkdtemp)
  592. def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3,
  593. lock_timeout = 172800): # two days
  594. """ return unique directory with a number greater than the current
  595. maximum one. The number is assumed to start directly after prefix.
  596. if keep is true directories with a number less than (maxnum-keep)
  597. will be removed.
  598. """
  599. if rootdir is None:
  600. rootdir = cls.get_temproot()
  601. def parse_num(path):
  602. """ parse the number out of a path (if it matches the prefix) """
  603. bn = path.basename
  604. if bn.startswith(prefix):
  605. try:
  606. return int(bn[len(prefix):])
  607. except ValueError:
  608. pass
  609. # compute the maximum number currently in use with the
  610. # prefix
  611. lastmax = None
  612. while True:
  613. maxnum = -1
  614. for path in rootdir.listdir():
  615. num = parse_num(path)
  616. if num is not None:
  617. maxnum = max(maxnum, num)
  618. # make the new directory
  619. try:
  620. udir = rootdir.mkdir(prefix + str(maxnum+1))
  621. except py.error.EEXIST:
  622. # race condition: another thread/process created the dir
  623. # in the meantime. Try counting again
  624. if lastmax == maxnum:
  625. raise
  626. lastmax = maxnum
  627. continue
  628. break
  629. # put a .lock file in the new directory that will be removed at
  630. # process exit
  631. if lock_timeout:
  632. lockfile = udir.join('.lock')
  633. mypid = os.getpid()
  634. if hasattr(lockfile, 'mksymlinkto'):
  635. lockfile.mksymlinkto(str(mypid))
  636. else:
  637. lockfile.write(str(mypid))
  638. def try_remove_lockfile():
  639. # in a fork() situation, only the last process should
  640. # remove the .lock, otherwise the other processes run the
  641. # risk of seeing their temporary dir disappear. For now
  642. # we remove the .lock in the parent only (i.e. we assume
  643. # that the children finish before the parent).
  644. if os.getpid() != mypid:
  645. return
  646. try:
  647. lockfile.remove()
  648. except py.error.Error:
  649. pass
  650. atexit.register(try_remove_lockfile)
  651. # prune old directories
  652. if keep:
  653. for path in rootdir.listdir():
  654. num = parse_num(path)
  655. if num is not None and num <= (maxnum - keep):
  656. lf = path.join('.lock')
  657. try:
  658. t1 = lf.lstat().mtime
  659. t2 = lockfile.lstat().mtime
  660. if not lock_timeout or abs(t2-t1) < lock_timeout:
  661. continue # skip directories still locked
  662. except py.error.Error:
  663. pass # assume that it means that there is no 'lf'
  664. try:
  665. path.remove(rec=1)
  666. except KeyboardInterrupt:
  667. raise
  668. except: # this might be py.error.Error, WindowsError ...
  669. pass
  670. # make link...
  671. try:
  672. username = os.environ['USER'] #linux, et al
  673. except KeyError:
  674. try:
  675. username = os.environ['USERNAME'] #windows
  676. except KeyError:
  677. username = 'current'
  678. src = str(udir)
  679. dest = src[:src.rfind('-')] + '-' + username
  680. try:
  681. os.unlink(dest)
  682. except OSError:
  683. pass
  684. try:
  685. os.symlink(src, dest)
  686. except (OSError, AttributeError, NotImplementedError):
  687. pass
  688. return udir
  689. make_numbered_dir = classmethod(make_numbered_dir)
  690. def copychunked(src, dest):
  691. chunksize = 524288 # half a meg of bytes
  692. fsrc = src.open('rb')
  693. try:
  694. fdest = dest.open('wb')
  695. try:
  696. while 1:
  697. buf = fsrc.read(chunksize)
  698. if not buf:
  699. break
  700. fdest.write(buf)
  701. finally:
  702. fdest.close()
  703. finally:
  704. fsrc.close()
  705. def isimportable(name):
  706. if name:
  707. if not (name[0].isalpha() or name[0] == '_'):
  708. return False
  709. name= name.replace("_", '')
  710. return not name or name.isalnum()