Source code for IMTreatment.utils.files

# -*- coding: utf-8 -*-
#!/bin/env python3

# Copyright (C) 2003-2007 Gaby Launay

# Author: Gaby Launay  <gaby.launay@tutanota.com>
# URL: https://framagit.org/gabylaunay/IMTreatment
# Version: 1.0

# This file is part of IMTreatment.

# IMTreatment is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.

# IMTreatment is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import warnings
import numpy as np
import shutil
import os
from os.path import join
import copy
import re
from ..utils.types import ARRAYTYPES
from ..utils.progresscounter import ProgressCounter

try:
    import colorama
except ImportError:
    colorama = None

[docs]class Files(object): def __init__(self): """ Class representing a bunch of files (and/or folders) """ self.paths = [] self.exist = [] self.isdir = [] def __add__(self, obj): if isinstance(obj, Files): tmp_files = self.copy() tmp_files.paths += obj.paths tmp_files.exist += obj.exist tmp_files.isdir += obj.isdir return tmp_files def __repr__(self): text = self.get_tree_representation(max_file_list=10, hide_top=True) return text
[docs] def get_tree_representation(self, max_file_list=10, hide_top=False): self.build_tree() # properties tab_color = "" folder_color = "" file_color = "" file_number_color = "" tab0 = "|" tab1 = tab0 + ">" + tab0 tab2 = tab0 + " " separator = "/" heading_separator = "=" if colorama is not None: tab_color = colorama.Fore.BLACK + colorama.Style.BRIGHT tab0 = tab_color + tab0 + colorama.Style.NORMAL tab1 = tab_color + tab1 + colorama.Style.NORMAL tab2 = tab_color + tab2 + colorama.Style.NORMAL folder_color = colorama.Fore.BLACK file_color = colorama.Fore.GREEN file_number_color = colorama.Fore.CYAN folders_end_of_line = "\n" files_end_of_line = "\n" max_file_list = max_file_list # recursion function def get_info_for_folder(fold, tab1, tab2): if not isinstance(fold, dict): raise TypeError() # if too much files to display, display number of files if 'files' in list(fold.keys()): if len(fold['files']) > max_file_list: yield (tab1 + file_number_color + '[{} Files]'.format(len(fold['files'])) + files_end_of_line) # loop recursively on folder's folders for key in list(fold.keys()): if key == 'files': pass else: yield tab1 + folder_color + key + folders_end_of_line for thing in get_info_for_folder(fold[key], tab1, tab2): yield tab2 + thing # loop on folder's files if 'files' in list(fold.keys()): if len(fold['files']) <= max_file_list: for f in fold['files']: yield tab1 + file_color + f + files_end_of_line # get text = "" tree = self.tree # add heading wih common path if hide_top: curr_fold = self.tree while True: if isinstance(curr_fold, dict): if len(list(curr_fold.keys())) == 1 and \ list(curr_fold.keys())[0] != "files": text += list(curr_fold.keys())[0] + separator curr_fold = curr_fold[list(curr_fold.keys())[0]] else: break else: break # put a nice heading text = text[:-1] heading_sep = heading_separator*(len(text)+2) text = (tab0 + tab_color + heading_sep + tab0 + folders_end_of_line + tab0 + " " + text + " " + tab0 + folders_end_of_line + tab_color + tab0 + tab_color + heading_sep + tab0 + folders_end_of_line) # update folder tree = curr_fold # display the tree for thing in get_info_for_folder(tree, tab1=tab1, tab2=tab2): text += thing return text
[docs] def copy(self): return copy.deepcopy(self)
[docs] def add_file(self, path): # check argument type try: path = str(path) except: raise TypeError() # check if valid path or not path = os.path.normpath(path) if os.path.exists(path): self.paths.append(path) self.exist.append(True) if os.path.isdir(path): self.isdir.append(True) else: self.isdir.append(False) elif os.access(os.path.dirname(path), os.W_OK): self.paths.append(path) self.exist.append(False) self.isdir.append(None) else: raise Exception()
[docs] def remove_files(self, arg): """ Remove some files from the files set. Parameters ---------- arg : integer, regex or array of integer or regex If integer, remove the associated path, if a regex, remove the paths that match, if an array, delete paths for each element. """ if isinstance(arg, int): ind = arg del self.paths[ind] del self.exist[ind] del self.isdir[ind] elif isinstance(arg, ARRAYTYPES): for thing in arg: self.remove_files(thing) elif isinstance(arg, str): for i in np.arange(len(self.paths) - 1, -1, -1): res = re.match(arg, self.paths[i]) if res is not None: print("remove {}".format(self.paths[i])) self.remove_files(i) else: raise TypeError()
[docs] def remove_empty_directories(): """ """ pass
[docs] def load_files_from_regex(self, rootpath, regex, load_files=True, load_dirs=True, depth='all'): """ Load existing files from a regular expression. """ # get folder names paths = [] isdir = [] exist = [] rootpath = os.path.normpath(rootpath) for root, dirs, files in os.walk(rootpath, topdown=True): # check depth if depth != "all": tmp_depth = (root[len(rootpath) + len(os.path.sep):] .count(os.path.sep)) if depth < tmp_depth: break # load direcories if load_dirs: for d in dirs: fullpath = join(root, d) if re.match(regex, fullpath): paths.append(fullpath) isdir.append(True) exist.append(True) # load files if load_files: for f in files: fullpath = join(root, f) if re.match(regex, fullpath): paths.append(fullpath) isdir.append(False) exist.append(True) # store self.paths += paths self.isdir += isdir self.exist += exist
[docs] def build_tree(self): """ Build a file tree """ dic = {} for isdir, path in zip(self.isdir, self.paths): sep_path = path.split(os.path.sep) tmp_dic = dic sep_path_len = len(sep_path) for i, fold in enumerate(sep_path): # folders if isdir or i != sep_path_len - 1: if fold in list(tmp_dic.keys()): tmp_dic = tmp_dic[fold] else: new_dic = {} tmp_dic[fold] = new_dic tmp_dic = new_dic # files () else: if 'files' in list(tmp_dic.keys()): tmp_dic['files'].append(fold) else: tmp_dic['files'] = [fold] # store self.tree = dic
[docs] def delete_existing_files(self, recursive=False): tmp_isdir = list(np.array(self.isdir)[np.array(self.exist)]) tmp_paths = list(np.array(self.paths)[np.array(self.exist)]) nmb_dir = np.sum(tmp_isdir) nmb_files = len(tmp_paths) - nmb_dir print("+++ Ready to remove {} files and {} directories " .format(nmb_files, nmb_dir)) while True: rep = input("+++ Okay with that ? ('o', 'n') \n+++ ") if rep in ['o', 'O', 'y', 'Y', 'oui', 'Oui', 'Yes', 'yes', 'YES', 'OUI']: rep = True break elif rep in ['n', 'N', 'No', 'no', 'non', 'Non', 'NON', 'NO']: rep = False break # remove if necessary if rep: print("") PG = ProgressCounter(init_mess="Begin cleaning", nmb_max=nmb_files, name_things='files', perc_interv=10) # remove files for i, p in enumerate(np.array(tmp_paths)): if tmp_isdir[i]: continue PG.print_progress() os.remove(p) # remove dirs for i, p in enumerate(np.array(tmp_paths)): if tmp_isdir[i]: # force recursive removing if recursive: shutil.rmtree(p) else: # else, check if each folder is empty try: os.rmdir(p) except WindowsError: print("+++ Following folder is not empty\n" "{}".format(p)) while True: rep = input("+++ Delete anyway ? ('o', 'n') " "\n+++ ") if rep in ['o', 'O', 'y', 'Y', 'oui', 'Oui', 'Yes', 'yes', 'YES', 'OUI']: rep = True break elif rep in ['n', 'N', 'No', 'no', 'non', 'Non', 'NON', 'NO']: rep = False break if rep is True: shutil.rmtree(p) # for i in range(len(self.exist)): self.exist[i] = False
[docs]def remove_files_in_dirs(rootpath, dir_regex, file_regex, depth='all', remove_dir=False, remove_files=True): """ make a recursive search for directories satisfying "dir_regex' from "rootpath", and remove all the files satisfying 'file_regex' in it. Parameters ---------- rootpath : string Path where to begin searching. dir_regex : string Regular expression matching the directory where we want to remove stuff. file_regex : string Regular expression matching the files we want to delete. depth : integer or 'all' Number of directory layer to go through. remove_dir : """ warnings.warn("Deprecated, use 'Files' class instead") # ### TODO : add the possibility to remove empty directories # get dirs dir_paths = [] nmb_files = [] file_paths = [] nmb_tot_files = 0 for root, dirs, files in os.walk(rootpath): nmb_tot_files += len(files) if re.match(dir_regex, root): tmp_nmb_files = 0 for f in files: if re.match(file_regex, f): tmp_nmb_files += 1 file_paths.append(os.path.join(root, f)) # check if there is actuelly files in there if not tmp_nmb_files == 0: nmb_files.append(tmp_nmb_files) dir_paths.append(root) # ask before deletion print("") print("+++ Checked {} files".format(nmb_tot_files)) if np.sum(nmb_files) == 0: print("+++ Nothing to delete") return None print("+++ Ready to remove {} files in directories :" .format(np.sum(nmb_files))) for i in range(len(dir_paths)): print("+++ [{} files] {}".format(nmb_files[i], dir_paths[i])) while True: rep = input("+++ Okay with that ? ('o', 'n') \n+++ ") if rep in ['o', 'O', 'y', 'Y', 'oui', 'Oui', 'Yes', 'yes', 'YES', 'OUI']: rep = True break elif rep in ['n', 'N', 'No', 'no', 'non', 'Non', 'NON', 'NO']: rep = False break # remove if necessary if rep: print("") PG = ProgressCounter(init_mess="Begin cleaning", nmb_max=len(file_paths), name_things='files', perc_interv=10) for p in file_paths: PG.print_progress() os.remove(p)