Lister les chemins qui posent problème

Code Python

"""  Code Python 3.9, encodé en UTF-8

Ce programme liste le nom des dossiers et des fichiers qui ne respecte pas
la règle 66 et ayant plus de 32 caractères.

Pour ne pas nuire à la rapidité, le programme ne mentionne pas les fichiers
commençant par . ou par ~, ayant un chiffre dans les 3 premiers caractères,
contenant --, ...

version 4 - 2022-11-20 00:09 - À Â Ç É È Ê Ë Î Ï Ô Ù Û Ü Ÿ Æ Œ æ œ """

# Les importations =============================================================
import re; import os; import platform
from datetime import datetime; import datetime # import après from !
import tkinter as tk; from tkinter import *
from tkinter import messagebox; from tkinter import filedialog

# Affectations des constantes pour les noms ====================================
DIGIT = "0123456789"                                           # = 10 caractères
ALPHA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" # = 52 caractères
FILENAME = ALPHA+DIGIT+"-_" # nom de fichier sans extension    # = 64 caractères
CARAC_66 = FILENAME+".~"# les 66 caractères simples dans une URL (fichier)

NB_CARAC_MAX = 32
NL = "\n"; DIR_DEV="/zZ" # ne pas modifier ce nom cfr "analysDir.py"

# Les déclarations des variables globales pour les fichiers ====================
gPath = os.path.abspath("."); SEP="/"
if platform.system() == "Windows": SEP="\\"#; gPath=os.path.abspath("C:\\Users");

# Création de l'interface
root = Tk ()
root.withdraw()

def regEx(mot, caracOK = CARAC_66, longMin = 1, longMax = NB_CARAC_MAX,
          isVerbeux = False): #--------------------------------------------------
  """
  La fonction retourne True ou False selon que le mot correspond au pattern ou pas.

  ..warning:: Le mot doit être débarassé des espaces du début et de fin
    avant d'être envoyé à cette fonction, car elle ne modifie pas le mot passé
    à la fonction. "     123  " (au lieu de "123") pourrait être enregistré dans la DB

  :param str mot: La string à tester.
  :param str caracOK: DIGIT | ALPHA | FILENAME | CARAC_66
  :param str longMin: Nombre minimal de caractères
  :param int longMax: Nombre maximal de caractères
  :param bool isVerbeux: si True affiche des messages (si problème)

  Elle requiert : import re

  :return: Retourne True si le mot ne contient pas de caractères interdits
  :rtype: bool

  2022-10-15 14:47:00
  """

  if mot is None: return False

  if len(mot)<longMin:
    if isVerbeux: messagebox.showwarning("Trop court","Pas assez de caractères.")
    return False

  if len(mot)>longMax:
    if isVerbeux: messagebox.showwarning("Trop long","Trop de caractères.")
    return False

  mot2 = mot.replace("-","")

  try:
    if(re.search("[^"+caracOK+"]", mot2)): return False
  except:
    messagebox.showwarning("Recommencer","Certains caractères posent problème.")
    return False

  return True


def listDirs(rootdir, exclu = "", withParent = True): #-------------------------
  """
  Fonction (non récursive) qui utilise une boucle WHILE pour lister
  les dossiers-enfants (et petit-enfants)

  :param str rootdir: Chemin complet du dossier (parent)

  Exemple (sous Windows) = X:/dossiers/sous-dossiers   (sans slash final)
  NB : La valeur de "rootdir" provient de "filedialog.askdirectory()"
  => pas de "backslash" => pas X:\dossiers\sous-dossiers

  :param str exclu: String dans le chemin qui l'exclut

  Exemple : si exclu="zZ", les chemins suivants sont exclus :
  X:\dossiers\zZ\old
  X:\dossiers\sous-dossiers\zZ
  ...

  :param bool withParent : Si False, retourne que les descendants

  Requiert l'importation de : os

  :return: Un tableau contenant la liste des chemins du dossier parent et de
  ses dossiers descendants, utilisant le séparateur de l'OS,
  sans ce séparateur final

  Exemple (sous Windows) :
  X:\dossiers\sous-dossiers\enfant1
  X:\dossiers\sous-dossiers\enfant1\petit-enfant
  ...

  :rtype: list

  2022-11-19 19:27:04
  """

  dossiers = [] # liste des chemins du dossier-parent et de ses descendants
                # (avec le caractère de séparation des noms dépendant de l'OS)

  dossiers.append(rootdir) # ajoute le dossier parent
  i=0 # index en cours

  print("Recherche en cours ... dans :", rootdir,
        " exclure :", exclu,
        " avec parent :", str(withParent))

  if len(exclu)>0:
    while i < len(dossiers):
      x = dossiers[i]#; print(str(i), str(len(dossiers)))
      for file in os.listdir(x):
        d = os.path.join(x, file)
        if os.path.isdir(d):
          if exclu not in d : dossiers.append(d)
      i +=1
  else:
    while i < len(dossiers):
      x = dossiers[i]#; print(str(i), str(len(dossiers)))
      for file in os.listdir(x):
        d = os.path.join(x, file)
        if os.path.isdir(d): dossiers.append(d)
      i +=1

  if not withParent: dossiers.pop(0)

  return dossiers


# ==============================================================================
dossier = gPath
while True:

  gVerbeux = False
  lstDossiers = []
  lstDossiersKO = []
  gListFichiersKO = []

  # Sélection du dossier
  folder  = filedialog.askdirectory(initialdir = dossier, title = "Sélection d'un dossier")
  dossier = folder.replace("/",SEP) #; print(dossier) # chemin complet du dossier choisi

  if len(dossier)==0 : exit()
  if not os.path.exists(dossier+DIR_DEV): os.makedirs(dossier+DIR_DEV)
  #print("---", dossier)

  dossier = dossier.replace("/",SEP); isAll = False
  if messagebox.askyesno("Sous-dossiers",
                         "Faut-il étendre l'analyse aux sous-dossiers ?"):
    lstDossiers = listDirs(dossier); isAll = True
  else: lstDossiers.append(dossier)

  # À ce stade, la liste des dossiers à analyser (lstDossiers) est établie
  nbDossiers = len(lstDossiers)
  if nbDossiers > 10 :
    if not messagebox.askyesno(str(nbDossiers)+ " sous-dossiers !",
                               "Faut-il continuer ?"): print("Bye !"); exit()

  # Début de la création du rapport ----------------------------------------------
  # Création de la date-time du rapport
  rapport = datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S')
  rapport += " --- analysé par 'listNot66.py'"+NL

  if nbDossiers > 1 : rapport +="Dossier parent : "+dossier+NL+NL
  else: rapport +="Dossier : "+dossier+NL+NL

  nbFichiers = 0
  for d in lstDossiers:
    with os.scandir(d) as it:
      for entry in it:
        if entry.is_dir():
          if not regEx(entry.name): lstDossiersKO.append(d) # test sur le dernier sous-dossier
        if entry.is_file():
          nbFichiers +=1
          if not regEx(entry.name): gListFichiersKO.append(d+SEP+entry.name)

  # Création du fichier-rapport dans le dossier analysé
  nbDossiersKO = len(lstDossiersKO)
  nbFichiersKO = len(gListFichiersKO)
  rapport += "Nombre de noms de dossiers non conformes : "+str(nbDossiersKO)+" sur " +str(len(lstDossiers))+NL
  rapport += "Nombre de noms de fichiers non conformes : "+str(nbFichiersKO)+" sur " +str(nbFichiers)+NL+NL

  if nbDossiersKO >0 or nbFichiersKO >0:
    if messagebox.askyesno(str(nbDossiersKO+nbFichiersKO)+" noms non valides",
                           "Faut-il lister tous les noms ?"): gVerbeux = True
  if gVerbeux:

    if len(lstDossiersKO)>0:
      rapport += "Liste des dossiers ayant un nom"+NL
      rapport += "de plus de "+str(NB_CARAC_MAX)+" caractères et/ou non conforme à la 'règle 66' :"+NL+NL
      bloc = ""
      for d in lstDossiersKO: bloc += d+NL
      if len(bloc)>0: rapport += bloc+NL+NL

    if len(gListFichiersKO)>0:
      rapport += "Liste des fichiers ayant un nom"+NL
      rapport += "de plus de "+str(NB_CARAC_MAX)+" caractères et/ou non conforme à la 'règle 66' :"+NL+NL
      bloc = ""
      for d in gListFichiersKO: bloc += d+NL
      if len(bloc)>0: rapport += bloc

  print(rapport)

  if messagebox.askyesno(dossier, "Faut-il y créer le fichier-rapport ?"):
    cc = dossier+DIR_DEV+"/listNot66.txt"
    try:
      f = open(cc, "w", encoding='utf-8'); f.write(rapport); print(cc+" créé."+NL+"."*80+NL+NL)
    except:
      print("Impossible d'écrire "+cc)
      messagebox.showerror("Impossible d'enregistrer le rapport",cc)
    finally:
      try:
        f.close()  # Fermer un fichier dans tous les cas (= bonne pratique)
      except:
        print("Le fichier n'a pas été fermé")

  if not messagebox.askyesno("Encore ?","Faut-il analyser un autre dossier ?"): break

root.destroy()
root.mainloop()