| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- # python3X
- """
- Convenient methods for managing files and directories
- @author: olivier.massot
- """
- import os
- import re
- import shutil
- import subprocess
- import sys
- import tempfile
- __VERSION__ = "0.2"
- def fdir(path):
- """return the parent directory of the file or directory
- (no file existence control)"""
- if path[-1] == os.path.sep:
- path = os.path.dirname(path)
- return os.path.normpath(os.path.dirname(path))
- def fname(path, with_ext=True):
- """return the name of the file
- with_ext: return the name with its extension
- (no file existence control)"""
- if not with_ext:
- path, _ = os.path.splitext(path)
- if path[-1] == os.path.sep:
- path = os.path.dirname(path)
- return os.path.basename(path)
- def fext(path):
- """return the extension of the file
- (no file existence control)"""
- return os.path.splitext(path)[1]
- def fabs(path):
- """ return the absolute expanded normalized path """
- return os.path.abspath(os.path.expandvars(os.path.expanduser(path)))
- def fexists(path):
- """test the existence of a file or directory"""
- return os.path.exists(os.path.normpath(path))
- def fisurl(instr):
- """return True if the 'instr' is a web url"""
- return re.match(r"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)", \
- instr)
- def fstart(path):
- """run/open the required file, directory, webpage... with the default software"""
- if not fisurl(path):
- path = os.path.normpath(path)
- if sys.platform == "win32":
- os.startfile(path)
- else:
- opener = "open" if sys.platform == "darwin" else "xdg-open"
- subprocess.call([opener, path])
- def flist(target_dir, files=True, dirs=False, recursive=True):
- """list the subdirectories and/or the files 'relative paths inside the directory
- """
- if not os.path.isdir(target_dir):
- raise NotADirectoryError("'{var}' is not an existing directory".format(var=target_dir))
- result = []
- for _root, _dirs, _files in os.walk(target_dir):
- rel_dir = os.path.relpath(_root, target_dir)
- if dirs:
- result += map(lambda p: (os.path.join(rel_dir, p) if rel_dir != "." else p), _dirs)
- if files:
- result += map(lambda p: (os.path.join(rel_dir, p) if rel_dir != "." else p), _files)
- if not recursive:
- break
- return result
- def ftree(dirpath):
- """ return a set (unordered) of the paths of the sub-directories
- """
- result = set()
- for sdpath in (os.path.join(dirpath, dirname) for dirname \
- in os.listdir(dirpath)):
- if os.path.isdir(sdpath):
- sdpath = os.path.normpath(sdpath)
- result |= ({sdpath} | ftree(sdpath))
- return result
- def fcopy(source, targetdir, rename_as="", erase=False):
- """ copy the file to the target directory
- > return the path of the newly created file
- """
- source = fabs(source)
- targetdir = fabs(targetdir)
- if not os.path.isdir(targetdir):
- raise NotADirectoryError("'targetdir' has to be a directory (given: {})".format(targetdir))
- target_name, target_ext = os.path.splitext(fname(source)) if not rename_as else os.path.splitext(rename_as)
- targetpath = os.path.join(targetdir, '%s%s' % (target_name, target_ext))
- if not erase and fexists(targetpath):
- targetpath = next((os.path.join(targetdir, '%s_%d%s' % (target_name, counter, target_ext)) for counter in range(2, 100000000) \
- if not fexists(os.path.join(targetdir, '%s_%d%s' % (target_name, counter, target_ext)))))
- shutil.copyfile(source, targetpath)
- return targetpath
- def faccess(path, mode="r"):
- """ return True if user has an access to the directory or file in parameter
- """
- path = os.path.normpath(path)
- if os.path.isfile(path):
- try:
- with open(path, mode) as _:
- pass
- return True
- except PermissionError:
- return False
- except FileNotFoundError:
- # could be a directory
- pass
- except OSError:
- pass
- if os.path.isdir(path):
- # try to explore as a directory
- if mode[0] == "r":
- try:
- next(os.walk(path))
- except StopIteration:
- return False
- return True
- else:
- try:
- with tempfile.TemporaryFile(mode=mode, dir=path) as _:
- pass
- return True
- except PermissionError:
- return False
- raise FileNotFoundError("'{path}' does not exist or is unaccessible".format(path=path))
- def fjoin(*args):
- """recursively normalize and join the paths in args"""
- return os.path.join(*[os.path.normpath(p) for p in args])
- def fmkdir(dirpath):
- """ create the directory if it do not exist """
- if not os.path.exists(dirpath):
- os.mkdir(dirpath)
- def fmktree(dirpath):
- """ create the directory recursively """
- if not os.path.exists(os.path.dirname(dirpath)):
- fmktree(os.path.dirname(dirpath))
- fmkdir(dirpath)
- def frmtree(dirpath):
- """recursively delete the directory, even it is not empty"""
- try:
- shutil.rmtree(dirpath)
- except FileNotFoundError:
- pass
- def fhumansize(size):
- """return a human readable size of file"""
- suffixes = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB']
- suffix_index = 0
- while size >= 1024:
- suffix_index += 1 # increment the index of the suffix
- size /= 1024.0 # apply the division
- return "{0:03.2f} {1}".format(size, suffixes[suffix_index]) if suffix_index > 0 \
- else "{0} {1}".format(size, suffixes[suffix_index])
- def fsub(dir1, dir2):
- """ return True if dir1 a sub-directory of dir2 """
- dir1, dir2 = map(fabs, [dir1, dir2])
- return os.path.commonprefix([dir1, dir2]) == dir2
|