Exemple #1
0
 def __new__(cls, *args, **kwargs):
     if kwargs.pop("expand", False):
         _ = expanduser(str(BasePath(*args, **kwargs)))
         p = BasePath(_, *args[1:], **kwargs).resolve()
         args = (str(p),) + args[1:]
     if kwargs.pop("create", False):
         BasePath(*args, **kwargs).mkdir(parents=True, exist_ok=True)
     return super(Path, cls).__new__(cls, *args, **kwargs)
Exemple #2
0
class Path(BasePath):
    """ Extension of the base class Path from pathlib.
    
    :param expand: expand user's path
    :param create: create the directory if it doesn't exist
    """
    _flavour = BasePath()._flavour  # fix to AttributeError

    def __new__(cls, *parts, **kwargs):
        expand = kwargs.pop("expand", False)
        create = kwargs.pop("create", False)
        _ = super(Path, cls).__new__(cls, *parts, **kwargs)
        if expand:
            _ = _.expanduser().absolute()
        if create and not _.exists():
            _.mkdir(parents=True)  # exist_ok does not work in Python 2
        return _

    @property
    def basename(self):
        """ Dummy alias for name attribute. """
        return self.name

    @property
    def bytes(self):
        """ Get file's content as bytes. """
        with self.open('rb') as f:
            return f.read()

    @property
    def child(self):
        """ Get the child path relative to self's one. """
        return Path(*self.parts[1:])

    @property
    def filename(self):
        """ Get the file name, without the complete path. """
        return self.stem + self.suffix

    @property
    def size(self):
        """ Get path's size. """
        if self.is_file() or self.is_symlink():
            return self.stat().st_size
        elif self.is_dir():
            s = 4096  # include the size of the directory itself
            for root, dirs, files in os.walk(str(self)):
                s += 4096 * len(dirs)
                for f in files:
                    s += os.stat(str(Path(root).joinpath(f))).st_size
            return s

    @property
    def text(self):
        """ Get file's content as a string. """
        return self.read_text()

    def __add_text(self, data, mode='w', encoding=None, errors=None):
        """ Allows to write/append text to the file, both in Python 2 and 3. """
        if not isinstance(data, string_types):
            raise TypeError("data must be str, not %s" %
                            data.__class__.__name__)
        with self.open(mode=mode, encoding=encoding, errors=errors) as f:
            return f.write(u(data))

    def append_bytes(self, data):
        """ Allows to append bytes to the file, as only write_bytes is available
             in pathlib, overwritting the former bytes at each write. """
        with self.open(mode='ab') as f:
            return f.write(memoryview(data))

    def append_line(self, line):
        """ Shortcut for appending a single line (text with newline). """
        self.append_text(["\n", ""][self.size == 0] + line)

    def append_lines(self, *lines):
        """ Shortcut for appending a bunch of lines. """
        for line in lines:
            self.append_line(line)

    def append_text(self, text, encoding=None, errors=None):
        """ Allows to append text to the file, as only write_text is available
             in pathlib, overwritting the former text at each write. """
        return self.__add_text(text, 'a', encoding, errors)

    def choice(self, *filetypes):
        """ Return a random file from the current directory. """
        if not self.is_dir():
            return self
        filetypes = list(filetypes)
        while len(filetypes) > 0:
            filetype = choice(filetypes)
            filetypes.remove(filetype)
            l = list(self.iterfiles(filetype, filename_only=True))
            if len(l) > 0:
                return self.joinpath(choice(l))

    def expanduser(self):
        """ Fixed expanduser() method, working for both Python 2 and 3. """
        return Path(os.path.expanduser(str(self)))

    def find(self, name=None, regex=False):
        """ Find a folder or file from the current path. """
        if name is None:
            f = lambda p: True
        elif not regex:
            if "*" not in name:
                f = lambda p: p.basename == name
            else:
                r = "^{}$".format(
                    name.replace(".", "\\.").replace("?", "\\?").replace(
                        "-",
                        "\\-").replace("+", "\\+").replace("[", "\\[").replace(
                            "]", "\\]").replace("(", "\\(").replace(
                                ")", "\\)").replace("{", "\\{").replace(
                                    "}", "\\}").replace("*", ".*"))
                f = lambda p: search(r, p.basename) is not None
        else:
            f = lambda p: search(name, p.basename) is not None
        for item in self.walk(filter_func=f):
            yield item

    def generate(self,
                 prefix="",
                 suffix="",
                 length=8,
                 alphabet="0123456789abcdef"):
        """ Generate a random folder name. """
        if not self.is_dir():
            return self
        while True:
            _ = "".join(choice(alphabet) for i in range(length))
            new = self.joinpath(str(prefix) + _ + str(suffix))
            if not new.exists():
                return new

    def is_hidden(self):
        """ Check if the current path is hidden. """
        if DARWIN:
            fnd = import_module("Foundation")
            u, f = fnd.NSURL.fileURLWithPath_(str(self)), fnd.NSURLIsHiddenKey
            return u.getResourceValue_forKey_error_(None, f, None)[1]
        elif LINUX:
            return self.stem.startswith(".")
        elif WINDOWS:
            import win32api, win32con
            return win32api.GetFileAttributes(p) & \
                   (win32con.FILE_ATTRIBUTE_HIDDEN | \
                    win32con.FILE_ATTRIBUTE_SYSTEM)
        raise NotImplementedError("Cannot check for the hidden status on this"
                                  " platform")

    def is_samepath(self, otherpath):
        """ Check if both paths have the same parts. """
        return self.absolute().parts == Path(otherpath).absolute().parts

    def iterfiles(self, filetype=None, filename_only=False):
        """ List all files from the current directory. """
        for i in self.iterdir():
            if i.is_file() and (filetype is None or i.suffix == filetype):
                yield i.filename if filename_only else i

    def iterpubdir(self):
        """ List all visible subdirectories from the current directory. """
        for i in self.iterdir():
            if i.is_dir() and not i.is_hidden():
                yield i

    def listdir(self, filter_func=lambda p: True, sort=True):
        """ List the current path using the given filter. """
        l = os.listdir(str(self))
        if sort:
            l = sorted(l)
        for item in l:
            item = self.joinpath(item)
            if filter_func(item):
                yield item

    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
        """ Fix to non-existing argument exist_ok in Python 2. """
        arg = (exist_ok, ) if PYTHON3 else ()
        super(Path, self).mkdir(mode, parents, *arg)

    def read_lines(self, encoding=None, errors=None):
        """ Extra method for reading a file as lines. """
        for l in self.read_text(encoding, errors).splitlines():
            yield l

    def read_text(self, encoding=None, errors=None):
        """ Fix to non-existing method in Python 2. """
        with self.open(mode='r', encoding=encoding, errors=errors) as f:
            return f.read()

    def reset(self):
        """ Ensure the file exists and is empty. """
        with self.open('w') as f:
            pass

    def remove(self):
        """ Extension for removing a directory or a file. """
        if self.is_dir():
            rmtree(str(self))
        else:
            os.remove(str(self))

    def walk(self, breadthfirst=True, filter_func=lambda p: True, sort=True):
        """ Walk the current path for directories and files using os.listdir(),
             breadth-first or depth-first, sorted or not, based on a filter
             function. """
        if breadthfirst:
            for item in self.listdir(lambda p: not p.is_dir(), sort):
                if filter_func(item):
                    yield item
        for item in self.listdir(lambda p: p.is_dir(), sort):
            if breadthfirst and filter_func(item):
                yield item
            for subitem in item.walk(breadthfirst, filter_func):
                yield subitem
            if not breadthfirst and filter_func(item):
                yield item
        if not breadthfirst:
            for item in self.listdir(lambda p: not p.is_dir(), sort):
                if filter_func(item):
                    yield item

    def write_text(self, data, encoding=None, errors=None):
        """ Fix to non-existing method in Python 2. """
        return self.__add_text(data, 'w', encoding, errors)
Exemple #3
0
class Path(type(BasePath())):
    def ls(self):
        """When the path points to a directory, return a list of path objects
        of the directory contents
        """
        return [item for item in self.iterdir()]
Exemple #4
0
from pathlib import Path as BasePath
from shutil import copytree, copy2 as copy

PathType = type(BasePath())
PathCopy = 'project.core.path.Path'


class Path(PathType):
    def copy(self, destination: BasePath) -> None:
        if self.is_dir():
            func = copytree
            destination /= self.name
        else:
            func = copy

        src = str(self.resolve())
        dest = str(destination.resolve())

        func(src, dest)

    def clone(self) -> PathCopy:
        return type(self)(self)
Exemple #5
0
class Path(BasePath):
    """ Extension of the base class Path from pathlib.
    
    :param expand: expand user's path
    :param create: create the directory if it doesn't exist
    :param touch:  create the file if it doesn't exist (mutually exclusive with 'create')
    """

    _flavour = BasePath()._flavour  # fix to AttributeError
    
    def __new__(cls, *parts, **kwargs):
        expand = kwargs.pop("expand", False)
        create = kwargs.pop("create", False)
        touch  = kwargs.pop("touch", False)
        p = super(Path, cls).__new__(cls, *parts, **kwargs)
        if expand:
            p = super(Path, cls).__new__(cls, str(p.expanduser().absolute()), **kwargs)
        if create and touch:
            raise ValueError("Conflicting options ; 'create' creates a folder hwile 'touch' creates a file")
        elif (create or touch) and not p.exists():
            if create:
                p.mkdir(parents=True)  # exist_ok does not work in Python 2
            elif touch:
                p.touch()
        return p
    
    @property
    def basename(self):
        """ Dummy alias for name attribute. """
        return self.name
    
    @property
    def bytes(self):
        """ Get file's content as bytes. """
        with self.open('rb') as f:
            return f.read()
    
    @property
    def child(self):
        """ Get the child path relative to self's one. """
        return Path(*self.parts[1:])
    
    @property
    def dirname(self):
        """ Get the directory name. """
        return self if self.is_dir() else self.parent
    
    @property
    def extension(self):
        """ Get the extension based on the stem and suffix. """
        return self.suffix
    
    @property
    def filename(self):
        """ Get the file name, without the complete path. """
        return self.basename
    
    @property
    def mime_type(self):
        """ Get the MIME type of the current Path object. """
        return guess_type(str(self))[0]
    
    @property
    def permissions(self):
        """ Get the permissions of the current Path object. """
        return os.stat(str(self)).st_mode
    
    @property
    def size(self):
        """ Get path's size. """
        if self.is_file() or self.is_symlink():
            return self.stat().st_size
        elif self.is_dir():
            s = 4096  # include the size of the directory itself
            for root, dirs, files in os.walk(str(self)):
                s += 4096 * len(dirs)
                for f in files:
                    s += os.stat(str(Path(root).joinpath(f))).st_size
            return s
    
    @property
    def stem(self):
        """ Stem also handling some common double extensions. """
        try:
            return DOUBLE_EXT.search(self.basename).group(1)
        except AttributeError:
            return super(Path, self).stem
    
    @property
    def suffix(self):
        """ Suffix also handling some common double extensions. """
        try:
            return DOUBLE_EXT.search(self.basename).group(2)
        except AttributeError:
            return super(Path, self).suffix
    
    @property
    def text(self):
        """ Get file's content as a string. """
        return self.read_text()
    
    def __add_text(self, data, mode='w', encoding=None, errors=None):
        """ Allows to write/append text to the file, both in Python 2 and 3. """
        if not isinstance(data, string_types):
            raise TypeError("data must be str, not %s" % 
                            data.__class__.__name__)
        with self.open(mode=mode, encoding=encoding, errors=errors) as f:
            return f.write(u(data))
    
    def append_bytes(self, data):
        """ Allows to append bytes to the file, as only write_bytes is available in pathlib, overwritting the former
             bytes at each write. """
        with self.open(mode='ab') as f:
            return f.write(memoryview(data))
    
    def append_line(self, line):
        """ Shortcut for appending a single line (text with newline). """
        self.append_text(["\n", ""][self.size == 0] + line)
    
    def append_lines(self, *lines):
        """ Shortcut for appending a bunch of lines. """
        for line in lines:
            self.append_line(line)
    
    def append_text(self, text, encoding=None, errors=None):
        """ Allows to append text to the file, as only write_text is available in pathlib, overwritting the former text
             at each write. """
        return self.__add_text(text, 'a', encoding, errors)
    
    def choice(self, *filetypes):
        """ Return a random file from the current directory. """
        if not self.is_dir():
            return self
        filetypes = list(filetypes)
        while len(filetypes) > 0:
            filetype = choice(filetypes)
            filetypes.remove(filetype)
            l = list(self.iterfiles(filetype, filename_only=True))
            if len(l) > 0:
                return self.joinpath(choice(l))
    
    def copy(self, new_path, **kwargs):
        """ Copy this folder or file to the given destination. """
        try:
            copytree(str(self), str(new_path), **kwargs)
        except OSError as e:  # does not use NotADirectoryError as it is only available from Python3
            if e.errno == errno.ENOTDIR:
                (copy2 if kwargs.pop('metadata', True) else copy)(str(self), str(new_path), **kwargs)
            else:
                return self
        return self.__class__(new_path)
    
    def expanduser(self):
        """ Fixed expanduser() method, working for both Python 2 and 3. """
        return Path(os.path.expanduser(str(self)))
    
    def find(self, name=None, regex=False):
        """ Find a folder or file from the current path. """
        if name is None:
            f = lambda p: True
        elif not regex:
            if "*" not in name:
                f = lambda p: p.basename == name
            else:
                r = "^{}$".format(name.replace(".", "\\.").replace("?", "\\?").replace("-", "\\-").replace("+", "\\+")
                                      .replace("[", "\\[").replace("]", "\\]").replace("(", "\\(").replace(")", "\\)")
                                      .replace("{", "\\{").replace("}", "\\}").replace("*", ".*"))
                f = lambda p: search(r, p.basename) is not None
        else:
            f = lambda p: search(name, p.basename) is not None
        for item in self.walk(filter_func=f):
            yield item
    
    def generate(self, prefix="", suffix="", length=8, alphabet="0123456789abcdef"):
        """ Generate a random folder name. """
        # simply return self if it exists and it is not a directory
        if self.exists() and not self.is_dir():
            return self
        # ensure this is a newly generated path
        while True:
            new = self.joinpath(str(prefix) + "".join(choice(alphabet) for i in range(length)) + str(suffix))
            if not new.exists():
                return new
    rand_folder_name = generate
    
    def is_hidden(self):
        """ Check if the current path is hidden. """
        if DARWIN:
            fnd = importlib.import_module("Foundation")
            u, f = fnd.NSURL.fileURLWithPath_(str(self)), fnd.NSURLIsHiddenKey
            return u.getResourceValue_forKey_error_(None, f, None)[1]
        elif LINUX:
            return self.stem.startswith(".")
        elif WINDOWS:
            import win32api, win32con
            return win32api.GetFileAttributes(p) & (win32con.FILE_ATTRIBUTE_HIDDEN | win32con.FILE_ATTRIBUTE_SYSTEM)
        raise NotImplementedError("Cannot check for the hidden status on this platform")
    
    def is_samepath(self, otherpath):
        """ Check if both paths have the same parts. """
        return self.absolute().parts == Path(otherpath).absolute().parts
    
    def is_under(self, parentpath):
        """ Check if the path is under a parent path. """
        p = Path(parentpath)
        if not p.is_dir():
            p = Path(p.dirname)
        return p in self.parents
    
    def iterfiles(self, filetype=None, filename_only=False, relative=False):
        """ List all files from the current directory. """
        for i in self.iterdir():
            if i.is_file() and (filetype is None or i.suffix == filetype):
                yield i.filename if filename_only else i.relative_to(self) if relative else i
    
    def iterpubdir(self):
        """ List all visible subdirectories from the current directory. """
        for i in self.iterdir():
            if i.is_dir() and not i.is_hidden():
                yield i
    
    def listdir(self, filter_func=lambda p: True, sort=True):
        """ List the current path using the given filter. """
        l = os.listdir(str(self))
        if sort:
            l = sorted(l)
        for item in l:
            item = self.joinpath(item)
            if filter_func(item):
                yield item
    
    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
        """ Fix to non-existing argument exist_ok in Python 2. """
        arg = (exist_ok, ) if PYTHON3 else ()
        super(Path, self).mkdir(mode, parents, *arg)
    
    def read_lines(self, encoding=None, errors=None):
        """ Extra method for reading a file as lines. """
        for l in self.read_text(encoding, errors).splitlines():
            yield l
    
    def read_text(self, encoding=None, errors=None):
        """ Fix to non-existing method in Python 2. """
        with self.open(mode='r', encoding=encoding, errors=errors) as f:
            return f.read()
    
    def reset(self):
        """ Ensure the file exists and is empty. """
        with self.open('w') as f:
            pass
    
    def remove(self, error=True):
        """ Extension for removing a directory or a file. """
        try:
            rmtree(str(self)) if self.is_dir() else os.remove(str(self))
        except OSError:
            if error:
                raise
    
    def walk(self, breadthfirst=True, filter_func=lambda p: True, sort=True, base_cls=True, relative=False):
        """ Walk the current path for directories and files using os.listdir(), breadth-first or depth-first, sorted or
             not, based on a filter function. """
        rel = lambda i: i.relative_to(self) if relative else i
        out = lambda i: Path(str(i)) if base_cls else i
        if breadthfirst:
            for item in self.listdir(lambda p: not p.is_dir(), sort):
                if filter_func(item):
                    yield out(rel(item))
        for item in self.listdir(lambda p: p.is_dir(), sort):
            if self.is_symlink() and self.resolve() == self.parent:
                continue  # e.g.: /usr/bin/X11 -> /usr/bin
            if breadthfirst and filter_func(item):
                yield out(rel(item))
            for subitem in item.walk(breadthfirst, filter_func, sort, base_cls):
                yield out(rel(subitem))
            if not breadthfirst and filter_func(item):
                yield out(rel(item))
        if not breadthfirst:
            for item in self.listdir(lambda p: not p.is_dir(), sort):
                if filter_func(item):
                    yield out(rel(item))
    
    def write_bytes(self, data):
        """ Fix to non-existing method in Python 2. """
        with self.open(mode='wb') as f:
            return f.write(memoryview(data))
    
    def write_text(self, data, encoding=None, errors=None):
        """ Fix to non-existing method in Python 2. """
        return self.__add_text(data, 'w', encoding, errors)
Exemple #6
0
 def __new__(cls, *args, **kwargs):
     if not cls._instance:
         cls._instance = BasePath(app('BASE_PATH'))
     return cls._instance
Exemple #7
0
class Path(BasePath):
    """ Extension of the base class Path from pathlib. """
    _flavour = BasePath()._flavour  # fix to AttributeError
    
    def __new__(cls, *args, **kwargs):
        if kwargs.pop("expand", False):
            _ = expanduser(str(BasePath(*args, **kwargs)))
            p = BasePath(_, *args[1:], **kwargs).resolve()
            args = (str(p),) + args[1:]
        if kwargs.pop("create", False):
            BasePath(*args, **kwargs).mkdir(parents=True, exist_ok=True)
        return super(Path, cls).__new__(cls, *args, **kwargs)
    
    @property
    def child(self):
        """ Get the child path relative to self's one. """
        return Path(*self.parts[1:])
    
    @property
    def filename(self):
        """ Get the file name, without the complete path. """
        return self.stem + self.suffix
    
    @property
    def size(self):
        """ Get path's size. """
        if self.is_file() or self.is_symlink():
            return self.stat().st_size
        elif self.is_dir():
            s = 4096  # include the size of the directory itself
            for root, dirs, files in os.walk(str(self)):
                s += 4096 * len(dirs)
                for f in files:
                    s += os.stat(str(Path(root).joinpath(f))).st_size
            return s
        raise AttributeError("object 'Path' has no attribute 'size'")
    
    def append_bytes(self, text):
        """ Allows to append bytes to the file, as only write_bytes is available
             in pathlib, overwritting the former bytes at each write. """
        with open(str(self), 'ab') as f:
            f.write(text)
    
    def append_line(self, line):
        """ Shortcut for appending a single line (text with newline). """
        self.append_text(line + '\n')
    
    def append_lines(self, *lines):
        """ Shortcut for appending a bunch of lines. """
        for line in lines:
            self.append_line(line)
    
    def append_text(self, text):
        """ Allows to append text to the file, as only write_text is available
             in pathlib, overwritting the former text at each write. """
        with open(str(self), 'a') as f:
            f.write(text)
    
    def choice(self, *filetypes):
        """ Return a random file from the current directory. """
        filetypes = list(filetypes)
        while len(filetypes) > 0:
            filetype = random.choice(filetypes)
            filetypes.remove(filetype)
            l = list(self.iterfiles(filetype, filename_only=True))
            try:
                return self.joinpath(random.choice(l))
            except:
                continue
    
    def expanduser(self):
        """ Fixed expanduser() method, working for both Python 2 and 3. """
        return Path(expanduser(str(self)))
    
    def generate(self, prefix="", suffix="", length=8,
                 alphabet="0123456789abcdef"):
        """ Generate a random folder name. """
        rname = "".join(random.choice(alphabet) for i in range(length))
        return self.joinpath(prefix + rname + suffix)
    
    def iterpubdir(self):
        """ List all public subdirectories from the current directory. """
        for i in self.iterdir():
            if i.is_dir() and not i.stem.startswith("."):
                yield i
    
    def iterfiles(self, filetype=None, filename_only=False, relative=False):
        """ List all files from the current directory. """
        for i in self.iterdir():
            if i.is_file():
                if filetype is None or i.suffix == filetype:
                    yield i.filename if filename_only else \
                          i.relative_to(self) if relative else i
    
    def read_text(self):
        """ Fix to non-existing method in Python 2. """
        try:
            super(Path, self).read_text()
        except AttributeError:  # occurs with Python 2 ; no write_text method
            with open(str(self), 'r') as f:
                c = f.read()
            return c
    
    def reset(self):
        """ Ensure the file exists and is empty. """
        if self.exists():
            self.unlink()
        self.touch()
    
    def rmtree(self):
        """ Extension for recursively removing a directory. """
        shutil.rmtree(str(self))
    
    def samepath(self, otherpath):
        """ Check if both paths have the same parts. """
        return self.parts == otherpath.parts
    
    def write_text(self, text):
        """ Fix to non-existing method in Python 2. """
        try:
            super(Path, self).write_text(text)
        except AttributeError:  # occurs with Python 2 ; no write_text method
            with open(str(self), 'w+') as f:
                f.write(text)