Contient le nouveau fichier README et 3 fichiers : - le script sur un seul fichier. - le nouveau modèle de Visa. - le fichier de style de couche (aucune modif, juste renommé) Ces 3 fichiers sont à copier dans le NextCloud pour mise à disposition.
1175 lines
40 KiB
Python
1175 lines
40 KiB
Python
## Version en un seul fichier du script banbou ##
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
# Vérifier s'il existe une version plus récente de pip
|
|
try:
|
|
result = subprocess.run(['pip', 'install', '--upgrade', 'pip', '--disable-pip-version-check'], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print("pip a été mis à jour avec succès.")
|
|
except subprocess.CalledProcessError:
|
|
print("La mise à jour de pip a échoué.")
|
|
|
|
bibliotheques = ['os', 'getpass', 're', 'shutil', 'datetime', 'openpyxl']
|
|
|
|
for bibliotheque in bibliotheques:
|
|
try:
|
|
__import__(bibliotheque)
|
|
except ImportError:
|
|
# Installer la bibliothèque
|
|
print(f"{bibliotheque} n'est pas installée. Installation en cours...")
|
|
subprocess.check_call(['pip', 'install', bibliotheque])
|
|
print(f"{bibliotheque} a été installée avec succès.")
|
|
|
|
|
|
|
|
|
|
import os, getpass
|
|
import re # module RegEx
|
|
import shutil, datetime
|
|
import openpyxl as xls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### CONSTANTES ###
|
|
|
|
|
|
# chemin absolue en dur du modèle
|
|
prenom = getpass.getuser()
|
|
MODELE = f"C:\\Users\\{prenom}\\Desktop\\Banbou\\VISA_BANBOU.xlsx"
|
|
|
|
|
|
# nom du dossier créé pour l'opérateur
|
|
TRAVAIL = "Travail"
|
|
|
|
|
|
# séparateur d'un CSV
|
|
SEP = ";"
|
|
|
|
|
|
# regex, motifs à chercher dans une chaine. Explication :
|
|
# (MOTIF)+ matche 1 OU PLUS occurence du mot MOTIF
|
|
# (?:) le groupe ne sera pas capturé, du coup dans python le groupe ne créé pas de chaine vide si pas de match du groupe en question
|
|
# | OR
|
|
EXPRESSION = r"(?:fiche)+|(?:relev)+|(?:topo)+|(?:ouvr)+|(?:\.doc)+|(?:\.dwg)+|(?:\.csv)+|(?:\.odt)+|(?:\.pdf)+|(?:\.doc)+"
|
|
|
|
|
|
# Masques Binaires représentants les controles de chaques catégorie traitées
|
|
# les bits sont allumés à chaque position où un test existe
|
|
FAIL_CSV = 7 # Explication : il existe pour le moment 3 tests pour les CSVs donc : "0000 0000 0000 0111"
|
|
FAIL_DWG = 16 # un seul test pour les DWGs : "0000 0000 0001 0000"
|
|
FAIL_PDF = 256 # un seul test pour les PDFs : "0000 0001 0000 0000"
|
|
FAIL_INFO = 4096 # un seul test pour les fiches infos : "0001 0000 0000 0000"
|
|
|
|
|
|
# Valeurs constantes définie par IGN
|
|
PROJECTIONS = [
|
|
{
|
|
"nom" : "GPS",
|
|
"E0" : 0,
|
|
"N0" : 0,
|
|
"offsetE0" : 180,
|
|
"offsetN0" : 90,
|
|
"EPSG" : 4326 # Correspond à la projection des GPS
|
|
},
|
|
{
|
|
"nom" : "Lambert93",
|
|
"E0" : 700000,
|
|
"N0" : 6600000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 600000,
|
|
"EPSG" : 2154 # Attention la plus recente est 9794
|
|
},
|
|
{
|
|
"nom" : "CC42",
|
|
"E0" : 1700000,
|
|
"N0" : 1200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3942
|
|
},
|
|
{
|
|
"nom" : "CC43",
|
|
"E0" : 1700000,
|
|
"N0" : 2200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3943
|
|
},
|
|
{
|
|
"nom" : "CC44",
|
|
"E0" : 1700000,
|
|
"N0" : 3200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3944
|
|
},
|
|
{
|
|
"nom" : "CC45",
|
|
"E0" : 1700000,
|
|
"N0" : 4200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3945
|
|
},
|
|
{
|
|
"nom" : "CC46",
|
|
"E0" : 1700000,
|
|
"N0" : 5200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3946
|
|
},
|
|
{
|
|
"nom" : "CC47",
|
|
"E0" : 1700000,
|
|
"N0" : 6200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3947
|
|
},
|
|
{
|
|
"nom" : "CC48",
|
|
"E0" : 1700000,
|
|
"N0" : 7200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3948
|
|
},
|
|
{
|
|
"nom" : "CC49",
|
|
"E0" : 1700000,
|
|
"N0" : 8200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3949
|
|
},
|
|
{
|
|
"nom" : "CC50",
|
|
"E0" : 1700000,
|
|
"N0" : 9200000,
|
|
"offsetE0" : 600000,
|
|
"offsetN0" : 111000,
|
|
"EPSG" : 3950
|
|
}
|
|
# TODO : ajouter les projections DOMTOMs
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### CLASSES ET FONCTIONS
|
|
|
|
|
|
class _Fichier:
|
|
|
|
|
|
def __init__(self,
|
|
#nom_original="Pas de nom original",
|
|
chemin="Pas de chemin",
|
|
extension="Pas d'extension",
|
|
nom= "Pas de nom",
|
|
implication="Non-conforme",
|
|
categorie="Pas de catégorie",
|
|
taille=0):
|
|
#self.nom_original = nom_original # - son nom original
|
|
self.chemin = chemin # - son chemin absolue (dossier+fichier+extension)
|
|
self.extension = extension # - son extension (ecrit en minuscule)
|
|
self.nom = nom # - son nom formaté
|
|
self.implication = implication # - son implication dans le projet {"Necessaire", "Non-conforme", "A-ignorer"}
|
|
self.categorie = categorie # - sa categorie {"CSV", "DWG", "SHEMAS", "TOPO", "Non-definie"}
|
|
self.taille = taille # taille en octets
|
|
|
|
|
|
def afficher(self):
|
|
"""
|
|
Affiche dans la sortie standard les éléments du fichier
|
|
"""
|
|
print("\nfichier.afficher()")
|
|
print("nom :".ljust(16) + self.nom)
|
|
#print("nom orig :".ljust(16) + self.nom_original)
|
|
print("ext :".ljust(16) + self.extension)
|
|
print("chemin :".ljust(16) + self.chemin)
|
|
print("implication :".ljust(16) + self.implication)
|
|
print("categorie :".ljust(16) + self.categorie)
|
|
print("taille :".ljust(16) + str(self.taille) )
|
|
|
|
|
|
def lire(dossier, fichier):
|
|
"""
|
|
Lit le nom du fichier et du dossier
|
|
|
|
Construit un élement _Fichier ET met à jour TOUS ses attributs
|
|
:param user_input: chemin absolue du dossier, nom du fichier
|
|
:return: un element _Fichier
|
|
"""
|
|
print("\nfichier.lire()")
|
|
# initialiser un _Fichier
|
|
ce_Fichier = _Fichier()
|
|
|
|
# son chemin absolue
|
|
ce_Fichier.chemin = dossier + "\\" + fichier
|
|
|
|
# déterminer son nom original et son extension
|
|
# vérifie qu'il y est au moins un point dans le nom
|
|
if "." in fichier :
|
|
|
|
*nom_original, ce_Fichier.extension = fichier.rsplit(".", maxsplit=1)
|
|
# reconstitue une chaine simple depuis la liste
|
|
nom_original = "".join(nom_original)
|
|
|
|
# lettrer l'extension en minuscule
|
|
ce_Fichier.extension = ce_Fichier.extension.casefold()
|
|
|
|
# formatter et écrire le nom
|
|
ce_Fichier.nom = formater(nom_original)
|
|
# déterminer son implication
|
|
ce_Fichier.implication, ce_Fichier.categorie = impliquer(fichier)
|
|
# calculer sa taille
|
|
ce_Fichier.taille = os.path.getsize(ce_Fichier.chemin)
|
|
print(f"implication : {ce_Fichier.implication} {ce_Fichier.categorie}")
|
|
else:
|
|
print(f'"{fichier}" est un fichier sans extension --> Non-conforme.')
|
|
ce_Fichier.nom = fichier
|
|
ce_Fichier.implication = "Non-conforme"
|
|
#TODO: voir si il manque pas des données à lire ici pour pas bloquer le reste du prog
|
|
|
|
return ce_Fichier
|
|
|
|
|
|
|
|
|
|
|
|
class _Notification:
|
|
def __init__(self,
|
|
categorie="Pas de catégorie",
|
|
texte="Pas de texte"):
|
|
self.categorie = categorie # vu comme une énumération de l'ensemble {"CSV", "DWG", "PDF", "FRONT"} seule ces valeurs sont donc possible et traité par le script
|
|
self.texte = texte
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def controler(id_point, point_x, point_y):
|
|
"""
|
|
regarde si les coordonnées d'un point sont bien dans une des projections
|
|
autorisées
|
|
|
|
Contrainte :
|
|
- Pour le moment, ne peut reconnaitre que des projections
|
|
de points situés en France métropolitaine (Lambert93 et les 9 zones CC).
|
|
- Ce sont toutes des projections coniques depuis le pole nord --> la longitude (axe Ouest Est) n'est pas déformé par ces projections et donc reste valide.
|
|
Mais je vais aussi contraindre la longitude à la France métropolitaine, pour pas qu'un point situé en Russie par exemple apparaisse comme valide.
|
|
NOTE : On ne controle pas l'élevation (coord Z), ces projections ne prennent pas en compte l'élevation.
|
|
|
|
param user_input: un point de type (int, float, float) TODO: avoir si conversion nécessaire ou faire en chaine de carac
|
|
return: Une chaine nommant la projection trouvé sinon "Mauvaise projection"
|
|
"""
|
|
|
|
#print("\nprojection.controler()")
|
|
|
|
# projection à retourner
|
|
projection = "Mauvaise projection"
|
|
|
|
# NOTE : Une partie des ensembles de coordonnées de CC47 et de Lambert93 s'intersectionne :
|
|
# Lorsqu'un point de coordonnées (X, Y) se situe dans la plage 1100000, 1300000 pour X et
|
|
# la plage 3089000, 3311000 pour Y, alors ce point est à la fois valide en CC47 et en Lambert93
|
|
# Avant de déterminer la projection, je vais donc vérifier si le point à controler n'est pas dans cette plage
|
|
# Et notifier si necessaire
|
|
# TODO : exporter la notif. En fait non, pas d'export juste un avertissement dans le shell
|
|
if 6089000 < point_y < 6311000:
|
|
if 1100000 < point_x < 1300000:
|
|
print(f"AVERTISSEMENT : ID {ID_POINT} : SES COORDONNÉES PEUVENT ÊTRE INTERPRÉTER CORRECTEMENT COMME DU CC47 ET DU LAMBERT93.")
|
|
print("DANS LA PLUPART DES CAS, VOUS DEVREZ PROJETER LE FICHIER CSV EN CC47.")
|
|
|
|
|
|
# définie la projection conique Nord en regardant dans quelle intervalle la valeur se situe
|
|
for P in PROJECTIONS:
|
|
borne_basse = P["N0"] - P["offsetN0"]
|
|
borne_haute = P["N0"] + P["offsetN0"]
|
|
if borne_basse < point_y < borne_haute :
|
|
projection = P["nom"]
|
|
|
|
#print(f"Proj. conique Nord trouvé : {projection}")
|
|
print(f" --> {projection:10}")
|
|
|
|
# Controle la longitude
|
|
# TODO: refaire cette partie avec des variables et non des entiers literraux
|
|
longitude_correcte = False
|
|
match projection:
|
|
case "Lambert93":
|
|
if 100000 < point_x < 1300000 :
|
|
longitude_correcte = True
|
|
case "CC42" | "CC43" | "CC44" | "CC45" | "CC46" | "CC47" | "CC48" | "CC49" | "CC50":
|
|
if 1100000 < point_x < 2300000 :
|
|
longitude_correcte = True
|
|
case "GPS":
|
|
if -180 < point_x < 180:
|
|
longitude_correcte = True
|
|
case _:
|
|
pass
|
|
|
|
if not longitude_correcte :
|
|
projection = "Mauvaise projection"
|
|
print(f"AVERTISSEMENT : LONGITUDE DU POINT ID {ID_POINT} PAS EN MÉTROPOLE.")
|
|
|
|
return projection
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Analyse lexicale
|
|
|
|
|
|
|
|
def tokeniser(ligne): #Pas utilisé, je le laisse au cas ou.
|
|
"""
|
|
Tokenise une ligne de texte.
|
|
|
|
Lit en entrée une "ligne" d'un fichier texte, découpe la ligne en mots,
|
|
chaque mot étant séparé par le séparateur "sep".
|
|
Attendu : si un champ est vide alors la liste reçoit quand même un
|
|
item pour representer ce champ (une chaine vide "" qui peut servir
|
|
pour tester sa présence)
|
|
Retourne une liste des mots trouvés, ou une liste vide si aucun mot.
|
|
"""
|
|
sortie = []
|
|
|
|
# enleve les espaces superflues avant et après la chaine
|
|
tempo = ligne.strip()
|
|
tempo = tempo.split(sep=SEP)
|
|
|
|
#affichage test
|
|
print("tokeniser")
|
|
print(tempo)
|
|
|
|
# enlever les mots vides
|
|
for i in tempo:
|
|
print
|
|
if i not in '':
|
|
sortie.append(i)
|
|
|
|
return sortie
|
|
|
|
|
|
|
|
|
|
## Conversion, Formatage
|
|
|
|
|
|
def formater(chaine):
|
|
"""Formate selon nomenclature.
|
|
|
|
Formate la chaine de caractères passée en paramètre :
|
|
Enlève tous les accents français. Enlève la cédille du C.
|
|
Remplace les espaces ' ', les traits d'union '-' et les ''' apostrophes
|
|
par des tirets bas '_'.
|
|
Ne traite pas pour le moment le AE et OE ligaturé.
|
|
Si plusieurs '_' se suivent, les réduire à un seul.
|
|
"""
|
|
#TODO : gérer les accents sur majuscules
|
|
#TODO : amélioration ou exercice, utiliser la méthode str.translate() et maketrans
|
|
resultat = ""
|
|
precedent = None
|
|
for c in chaine:
|
|
match c:
|
|
case "à" | "â" | "ä":
|
|
resultat+= "a"
|
|
case "é" | "è" | "ê" | "ë":
|
|
resultat+= "e"
|
|
case "î" | "ï":
|
|
resultat+= "i"
|
|
case "ô" | "ö":
|
|
resultat+= "o"
|
|
case "ù" | "û" | "ü":
|
|
resultat+= "u"
|
|
case "ÿ":
|
|
resultat+= "y"
|
|
case "ç":
|
|
resultat+= "c"
|
|
case " " | "-" | "_" | "'":
|
|
if('_' not in precedent ):
|
|
resultat+= "_"
|
|
c = "_"
|
|
case _:
|
|
resultat+= c
|
|
precedent = c
|
|
return resultat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Analyse semantique
|
|
|
|
|
|
def impliquer(chaine):
|
|
"""
|
|
Définir l'implication d'une chaine (attendu : un nom de fichier avec son extension).
|
|
|
|
Retourne un tuple de str (Necessité, Catégorie).
|
|
|
|
La necessité peut prendre une des valeurs suivantes :
|
|
{"Necessaire", "A-ignorer}.
|
|
La catégorie peut prendre une des valeurs suivantes:
|
|
{"CSV", "DWG", "SHEMAS", "TOPO", "Non-definie"}.
|
|
Il est attendu que lorsqu'un fichier obtient une valeur de catégorie
|
|
Alors il est aussi considéré "Necessaire".
|
|
|
|
Les fichiers "Necessaire" seront les fichiers copiés dans le
|
|
répertoire "Travail".
|
|
|
|
La catégorie est définie par une recherche de motif dans le nom du fichier.
|
|
# TODO: voir si elle peut pas être définie en lisant les métadonnées des fichiers
|
|
|
|
Les fichiers nécessaires sont les DWGs, les CSVs pour les datas.
|
|
Pour les shémas et relevés de topo :
|
|
- PDFs, DOCs, ODTs (Doc LibreOffice),
|
|
"""
|
|
|
|
print(f"\nimpliquer({chaine})")
|
|
|
|
# mettre la chaine en minuscule
|
|
chaine = chaine.casefold()
|
|
|
|
# cherche la PREMIERE correspondance du motif (alors que findall() cherche toutes les correspodances)
|
|
motif = re.search(EXPRESSION, chaine)
|
|
|
|
if motif:
|
|
print("Il y a un match")
|
|
motif = motif.group()
|
|
else:
|
|
print("Pas de match")
|
|
|
|
match motif :
|
|
# On va traiter les mots clés d'abord
|
|
case "fiche" | "relev" | "topo" | "ouvr" | ".doc" | ".odt" :
|
|
return ("Necessaire", "TOPO")
|
|
case ".dwg" :
|
|
return ("Necessaire", "DWG")
|
|
case ".csv" :
|
|
return ("Necessaire", "CSV")
|
|
case ".pdf" :
|
|
return ("Necessaire", "SHEMAS")
|
|
case _ :
|
|
return ("A-ignorer","Non-definie")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _Projet:
|
|
|
|
|
|
def __init__(self,
|
|
nom="Pas de nom",
|
|
date="Pas de date",
|
|
racine="Pas de chemin",
|
|
fichiers=[],
|
|
nb_fichiers=0,
|
|
taille=0,
|
|
rapport="Pas de fichier",
|
|
nb_shemas=0,
|
|
nb_releves=0,
|
|
nb_csvs=0,
|
|
points=[],
|
|
nb_points=0,
|
|
nb_dwgs=0,
|
|
notifs=[],
|
|
controles=0):
|
|
self.nom = nom # nom du projet
|
|
self.date = date # date du traitement
|
|
self.racine = racine # chemin racine du projet
|
|
self.fichiers = fichiers # liste de _Fichier
|
|
self.nb_fichiers = nb_fichiers # nb de fichiers dans "Travail"
|
|
self.taille = taille # taille des fichiers dans "Travail"
|
|
self.rapport = rapport # chemin vers le visa
|
|
self.nb_shemas = nb_shemas # nb de plans de la mise en place
|
|
self.nb_releves = nb_releves # nb de rapports de relevés topo
|
|
self.nb_csvs = nb_csvs # nb de fichiers CSV
|
|
self.points = points # liste des points du CSV
|
|
self.nb_points = nb_points # nb de points des CSVs TODO: REDONDANT avec len(points)
|
|
self.nb_dwgs = nb_dwgs # nb de fichiers DWG
|
|
self.notifs = notifs # liste contenant les notifs du VISA
|
|
self.controles = controles # variable drapeau contenant toutes les validations de controles
|
|
# (voir Document pour plus d'info sur sa représentation)
|
|
|
|
def notifier(self, categorie, texte):
|
|
"""
|
|
Ajoute une notification au _Projet
|
|
"""
|
|
print("\n_Projet.notifier()")
|
|
print(f"Incident ajouté :{texte} ")
|
|
incident = _Notification( categorie, texte)
|
|
self.notifs.append(incident)
|
|
|
|
|
|
def lister_fichiers(self, dossier):
|
|
"""
|
|
Construit une liste avec les fichiers de 'dossier'
|
|
|
|
- Parcours le dossier et ses sous-dossiers, ajoute TOUS les fichiers
|
|
dans une liste de _Fichier.
|
|
- Chaque _Fichier ajouté a ses attributs mis a jour.
|
|
- Les nombres des différentes catégories de fichiers nécessaires
|
|
au projet sont mis a jour.
|
|
:param user_input: nom complet du dossier
|
|
:return: liste d'élements de type _Fichier
|
|
"""
|
|
print("\n_Projet.lister_fichiers()")
|
|
self.fichiers = []
|
|
|
|
print("Création liste de _Fichier...")
|
|
|
|
for dossier_courant, list_sousdossiers, list_fichiers in os.walk(dossier):
|
|
for fichier_courant in list_fichiers:
|
|
ce_Fichier = lire(dossier_courant, fichier_courant)
|
|
self.fichiers.append(ce_Fichier)
|
|
print(f'"{fichier_courant}" ajouté.')
|
|
|
|
# mettre à jour les nbs des catégories de fichiers necessaires
|
|
if ce_Fichier.implication in "Necessaire":
|
|
### sa categorie {"CSV", "DWG", "SHEMAS", "TOPO", "Non-definie"}
|
|
match ce_Fichier.categorie :
|
|
case "CSV":
|
|
self.nb_csvs += 1
|
|
case "DWG":
|
|
self.nb_dwgs += 1
|
|
case "SHEMAS":
|
|
self.nb_shemas += 1
|
|
case "TOPO":
|
|
self.nb_releves += 1
|
|
case _:
|
|
pass
|
|
|
|
print("Fin création liste.")
|
|
|
|
|
|
# TODO surcharger la fonction print native pour cet affichage
|
|
def afficher_liste(liste):
|
|
"""
|
|
Affiche le nom des fichiers de la liste des _Fichiers
|
|
"""
|
|
print("\nprojet.afficher_liste()")
|
|
for courant in liste:
|
|
print("\n" + courant.nom + "." + courant.extension)
|
|
|
|
|
|
def enraciner(projet):
|
|
"""
|
|
récupère le repertoire de travail (working directory) courant
|
|
met à jour l'attribut 'racine' d'un projet
|
|
"""
|
|
print("\nprojet.enraciner()")
|
|
projet.racine = os.getcwd()
|
|
print("Racine : ".ljust(16), f"{projet.racine}")
|
|
|
|
|
|
def calculer_taille(projet):
|
|
"""
|
|
calcule la taille des fichiers necessaires d'un liste
|
|
d'élements _Fichier.
|
|
Met à jour l'attribut 'taille' dans le projet
|
|
"""
|
|
print("\nprojet.calculer_taille()")
|
|
taille = 0.0
|
|
for courant in projet.fichiers:
|
|
if courant.implication in "Necessaire":
|
|
taille += courant.taille
|
|
projet.taille = taille
|
|
# Affichage adapté à la bonne unité
|
|
if taille < 1024 :
|
|
unite = "octets"
|
|
elif taille < 1024**2 :
|
|
unite = "Ko"
|
|
taille /= 1024
|
|
else :
|
|
unite = "Mo"
|
|
taille /= 1024**2
|
|
print(f"Taille totale : {taille:.2f} {unite}.")
|
|
|
|
|
|
def dater(projet):
|
|
"""
|
|
recupère la date du jour
|
|
met à jour l'attribut 'date' du projet
|
|
"""
|
|
print("\nprojet.dater()")
|
|
projet.date = datetime.datetime.today().strftime('%Y%m%d')
|
|
print(f"Date : {projet.date}")
|
|
|
|
|
|
def nommer(projet):
|
|
"""
|
|
Met à jour l'attribut 'nom' en composant un nom.
|
|
|
|
Le nom est constitué du NOM du dossier racine ET de la DATE
|
|
courante formatté.
|
|
|
|
"""
|
|
print("\nprojet.nommer()")
|
|
projet.nom = f"{os.path.basename(os.getcwd())}_{projet.date}"
|
|
projet.nom = formater(projet.nom)
|
|
print(f'Nom : "{projet.nom}"')
|
|
|
|
|
|
def preparer_dossier_travail(projet):
|
|
"""
|
|
Créer un dossier "Travail" dans la racine du working directory et
|
|
le peuple des fichiers nécessaires
|
|
|
|
Préfixe et suffixe les fichiers le nécessitant (le CSV et le DWG)
|
|
"""
|
|
print("\nprojet.preparer_dossier_travail()")
|
|
#travail = "Travail"
|
|
|
|
# création du dossier "Travail" et de ses sous-dossiers "
|
|
_chemin = f"{projet.racine}\\{TRAVAIL}"
|
|
#nomemclaturer les noms des sousdossiers
|
|
sousdossier = f"{_chemin}\\{projet.nom}"
|
|
|
|
# pour le moment tous les sous dossiers sont
|
|
dossierCSVs = _chemin
|
|
dossierDWGs = _chemin
|
|
dossierPDFs = _chemin
|
|
dossierTOPOs = _chemin
|
|
|
|
print(f'Chemin du dossier de préparation : "{_chemin}"')
|
|
try:
|
|
os.mkdir(_chemin)
|
|
print (f'Dossier "{TRAVAIL}" créé.')
|
|
os.mkdir(sousdossier) # dossier pour le projet ARCGIS
|
|
|
|
if projet.nb_csvs > 1:
|
|
dossierCSVs = f"{sousdossier}_CSV"
|
|
os.mkdir(dossierCSV)
|
|
print (f'Dossier "CSV" créé.')
|
|
if projet.nb_dwgs > 1:
|
|
dossierDWGs = f"{sousdossier}_DWG"
|
|
os.mkdir(dossierDWGs)
|
|
print (f'Dossier "DWG" créé.')
|
|
if projet.nb_shemas > 1:
|
|
dossierPDFs = f"{sousdossier}_PDF"
|
|
os.mkdir(dossierPDFs)
|
|
print (f'Dossier "PDF" créé.')
|
|
if projet.nb_releves > 1:
|
|
dossierTOPOs = f"{sousdossier}_TOPO"
|
|
os.mkdir(dossierTOPOs)
|
|
print (f'Dossier "TOPO" créé.')
|
|
|
|
except FileExistsError as erreur:
|
|
print(f'AVERTISSEMENT: LE DOSSIER "{TRAVAIL}" EXISTE DÉJA. SUPPRIMER LE, PUIS RELANCER LE SCRIPT SVP.')
|
|
purger_et_finir_programme(projet)
|
|
except OSError as erreur:
|
|
print(f"FICHIER NON TROUVÉ. SUREMENT UN PB DE CHEMIN EN AMONT.")
|
|
purger_et_finir_programme(projet)
|
|
|
|
|
|
|
|
# peuplement du dossier Travail avec les fichiers necessaires
|
|
print("Copie des fichiers nécessaires et nomenclature de leurs noms...")
|
|
for fichier in projet.fichiers:
|
|
if fichier.implication in "Necessaire":
|
|
source = fichier.chemin
|
|
print(f"source : {source}")
|
|
|
|
# fabrication du nom du fichier de destination
|
|
dest = _chemin + "\\"
|
|
|
|
# lors du peuplement préfixer et suffixer les noms des fichiers concernés comme suit : "Plan_nomfichierdwg.dwg" et "Point_nomfichiercsv_IN.csv"
|
|
# Confirmation par Audrey qu'il n'y a nécessairement qu'un fichier CSV par projet --> Le script s'occupe de le renommer.
|
|
# Mais parfois il peut y avoir plusieurs DWGs dont un seul est utile --> PASS -- Je laisse l'opérateur choisir lequel utiliser et le renommer manuellement.
|
|
|
|
#{"CSV", "DWG", "SHEMAS", "TOPO", "Non-definie"}
|
|
match fichier.categorie :
|
|
case "CSV":
|
|
dest = f"{dossierCSVs}\\Point_{fichier.nom}_IN"
|
|
case "DWG":
|
|
dest = f"{dossierDWGs}\\Plan_{fichier.nom}"
|
|
case "SHEMAS":
|
|
dest = f"{dossierPDFs}\\{fichier.nom}"
|
|
case "TOPO":
|
|
dest = f"{dossierTOPOs}\\{fichier.nom}"
|
|
case _:
|
|
pass # TODO: voir pour les autres cas, normalement il n'y en a pas pour le moment
|
|
|
|
dest = dest + f".{fichier.extension}"
|
|
print(f"dest : {dest}")
|
|
|
|
if fichier.implication in "Necessaire":
|
|
try:
|
|
shutil.copyfile( source , dest)
|
|
print("" + fichier.nom.ljust(40,".") + "copié")
|
|
except shutil.SameFileError as err :
|
|
print(f"Le fichier existe déjà.")
|
|
#TODO :
|
|
# Confirmation par Audrey qu'il n'y a necessairement qu'un fichier CSV par projet --> On peut le renommer.
|
|
# Mais parfois il peut y avoir plusieurs DWGs dont un seul est utile --> PASS -- Je laisse l'opérateur choisir lequel utiliser et le renommer manuellement. EDIT : Nathalie prefere que tous les fichier DWG soient préfixé avec Plan_
|
|
#TODO : verifier aussi la longueur des noms de fichiers. Notifier si nécessaire
|
|
|
|
|
|
def controler_longueur_noms(projet):
|
|
"""
|
|
controle la longueur des noms des fichiers du projet.
|
|
|
|
Notifie si necessaire les noms trop longs
|
|
"""
|
|
#print("\nprojet.controler_longueur_noms()")
|
|
for fichier in projet.fichiers:
|
|
match fichier.extension:
|
|
case "dwg":
|
|
if len(fichier.nom) > 25 : # Plan_ + 25 carac --> 30 carac
|
|
projet.notifier("DWG", f'"Plan_{fichier.nom}.dwg" : Nom trop long.')
|
|
case "csv" :
|
|
if len(fichier.nom) > 35 : # Point_ + 35 carac + _OUT --> 45 carac
|
|
projet.notifier("CSV", f'"Point_{fichier.nom}_IN.csv" : Nom trop long.')
|
|
case "pdf" :
|
|
if len(fichier.nom) > 45 :
|
|
projet.notifier("PDF", f'"{fichier.nom}.pdf" : Nom trop long.')
|
|
case _:
|
|
if len(fichier.nom) > 45 :
|
|
projet.notifier("FRONT", f'"{fichier.nom}.{fichier.extension}" : Nom trop long.')
|
|
|
|
def formater_vers_ArcGIS(projet, fichier_entree, fichier_sortie):
|
|
"""
|
|
Lit et formatte un fichier CSV pour son importation dans ArcGIS.
|
|
|
|
Lit la 1ère ligne et s'assure de la présence des titres de colonnes,
|
|
formatte cette 1ère ligne.
|
|
Supprime les lignes vides.
|
|
Change le séparateur décimal ',' en '.' (necessaire car sinon je ne peux convertir les strings en float)
|
|
Notifie si nécessaire les points de controles qui ne passent pas.
|
|
Met à jour l'attribut nb_points
|
|
Contraintes :
|
|
- Le fichier CSV NÉCESSITE des ';' comme séparateur d'élements. (Normalement c'est toujours le cas de toutes façon)
|
|
- Le fichier doit avoir exactement 5 colonnes. TODO : vois si plus de souplesse avec le catchage de paramètres restants
|
|
param user_input: nom complet d'un fichier csv
|
|
NOTE: Ne pas formatter le fichier original, mais celui qui est deja copié dans le dossier Travail
|
|
"""
|
|
print("\nprojet.formatter_vers_ArcGIS()")
|
|
|
|
# titres des colonnes correctement formattés.
|
|
titres = "id_point;TYPE;X;Y;Z\n"
|
|
|
|
sortie = [titres] # le fichier de sortie ( representé comme une liste de lignes ) contient un premiere ligne de titre
|
|
|
|
|
|
df = open(fichier_entree, "r")
|
|
ligne = df.readline()
|
|
|
|
# analyser la premiere ligne et formatter cette ligne
|
|
# Si le premier mot est un nombre Alors il manque les titres, dans
|
|
# ce cas insérer une ligne.
|
|
mots = ligne.split(sep=";", maxsplit=1)
|
|
print(f"Mots[0] = {mots[0]}")
|
|
|
|
|
|
if mots[0].isnumeric():
|
|
#insérer ligne
|
|
sortie.append(ligne)
|
|
projet.nb_points += 1
|
|
|
|
# la tête de lecture du descripteur de fichier ne reset pas sa position
|
|
# donc on peut continuer le parcours des lignes directement
|
|
for ligne_courante in df :
|
|
|
|
# lit et controle la ligne courante
|
|
courant = lire_et_controler_ligne(projet, ligne_courante)
|
|
# ajoute la ligne
|
|
if courant not in "":
|
|
sortie.append(f"{courant}\n")
|
|
# compter ce point
|
|
projet.nb_points += 1
|
|
|
|
df.close()
|
|
|
|
# je reouvre le descripteur en mode w only pour ecrire le fichier
|
|
df = open(fichier_sortie, "w")
|
|
# écriture
|
|
for ligne in sortie:
|
|
#print(f"{ligne}")
|
|
df.write(ligne) # NOTE: write()
|
|
|
|
df.close()
|
|
|
|
print("Fin formatage du CSV.")
|
|
|
|
|
|
def lire_et_controler_ligne(projet, ligne):
|
|
"""
|
|
Analyse une chaine de caractère (concrètement, une ligne du CSV)/
|
|
|
|
remplace les séparateurs décimaux ',' par '.'
|
|
Notifie (dans le projet lié) les points de controles qui ne passent pas.
|
|
Met à jour l'attribut nb_points du projet lié
|
|
Met à jour la variable de controles du projet lié
|
|
Contraintes :
|
|
- Le fichier CSV NÉCESSITE des ';' comme séparateur d'élements.
|
|
:return: une chaine de carac formatté pour ArcGIS
|
|
"""
|
|
#print("\nprojet.lire_et_controler_ligne()")
|
|
#print(f'ENTREE : "{ligne}"')
|
|
# enlever les espaces
|
|
ligne = ligne.replace(" ", "")
|
|
ligne = ligne.replace(",", ".")
|
|
ligne = ligne.replace("\n", "")
|
|
# si la ligne n'est pas vides alors
|
|
# TODO : changer le match en if ligne not in ["", ";;;;"]:
|
|
match ligne:
|
|
case ";;;;;;" | ";;;;;" | ";;;;" | ";;;" | ";;" | ";" | "" :
|
|
ligne = ""
|
|
case _:
|
|
# controler la projection de ce point
|
|
# NOTE: split() tokenise la ligne en items (des strings), si un champ est manquant, alors il tokenise une chaine vide( "" )
|
|
# On peut donc tester cette chaine vide pour savoir si une champ est manquant.abs
|
|
# Je vais dont controler la présence du champ ID, car il apparait que parfois il est manquant. Si tel est le cas,
|
|
# Notifier et terminer le programme --> dossier FAIL
|
|
#
|
|
# NOTE: split() n'enleve pas le \n de la fin de ligne dans la chaine --> ligne = ligne.replace("\n", "") que j'ai rajouter au dessus
|
|
try :
|
|
id_point, type_, point_x, point_y, point_z, *autres = ligne.split(sep=";")
|
|
except ValueError:
|
|
print("LE FICHIER SOURCE CSV EST MAL FORMATÉ, IL DOIT MANQUER DES CHAMPS ET DE SÉPARATEURS DE CHAMPS.")
|
|
purger_et_finir_programme(projet)
|
|
|
|
|
|
#PRINT de controle
|
|
print(f'ID:"{id_point}", TYPE:"{type_}", X:"{point_x}", Y:"{point_y}", Z:"{point_z}", *autres={autres}')
|
|
|
|
# controler qu'il n'y est pas un champ vide pour id_point, TYPE, X et Y. (Z étant optionnel)
|
|
# Si tel est le cas, on quitte FAIL
|
|
if id_point in "":
|
|
print('AVERTISSEMENT : COLONNE "ID_POINT" MANQUANTE.')
|
|
purger_et_finir_programme(projet)
|
|
if type_ in "":
|
|
print('AVERTISSEMENT : COLONNE "TYPE" MANQUANTE.')
|
|
purger_et_finir_programme(projet)
|
|
if point_x in "":
|
|
print('AVERTISSEMENT : COLONNE "X" MANQUANTE.')
|
|
purger_et_finir_programme(projet)
|
|
if point_y in "":
|
|
print('AVERTISSEMENT : COLONNE "Y" MANQUANTE.')
|
|
purger_et_finir_programme(projet)
|
|
if point_z in "":
|
|
print('AVERTISSEMENT : COLONNE "Z" MANQUANTE.')
|
|
purger_et_finir_programme(projet)
|
|
|
|
# controler que id_point est un entier
|
|
# Si c'est un flottant alors ya un pb, on quitte FAIL
|
|
try :
|
|
if float(id_point)/int(id_point) != 1.0 :
|
|
print("AVERTISSEMENT : LA PREMIÈRE COLONNE EST UN FLOTTANT. ATTENDU UN ID_POINT DE VALEUR ENTIÈRE.")
|
|
print('IL DOIT MANQUER LA COLONNE "ID_POINT AINSI QUE LE SÉPARATEUR DE CHAMP ";".')
|
|
purger_et_finir_programme(projet)
|
|
except ValueError :
|
|
print("AVERTISSEMENT : LA COLONNE ID_POINT N'A PAS UN NOMBRE.")
|
|
print(f'ATTENDU UN ENTIER. TROUVÉ ID_POINT DE TYPE "{type(id_point)}"')
|
|
purger_et_finir_programme(projet)
|
|
|
|
|
|
# A partir d'ici il est attendu que la tokenisation se soit bien déroulée
|
|
try :
|
|
projo = controler(id_point, float(point_x), float(point_y))
|
|
except ValueError :
|
|
print("AVERTISSEMENT : UNE COLLONNE (X OU Y) EST MAL CONVERTIE.")
|
|
print(f'ATTENDU VALEURS DÉCIMALES. TROUVÉ X : DE TYPE "{type(point_x)}", Y DE TYPE "{type(point_y)}"')
|
|
purger_et_finir_programme(projet)
|
|
# notifier si pas bonne projection
|
|
if projo in "Mauvaise projection":
|
|
incident = _Notification("CSV", f"Point ID {id_point} : Mauvaise projection")
|
|
projet.notifs.append(incident)
|
|
projet.controles |= 2**2
|
|
|
|
#print(f'SORTIE : "{ligne}"')
|
|
|
|
return ligne
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remplir(modele, projet):
|
|
"""
|
|
Complète le Visa du projet à partir d'un fichier modele.
|
|
|
|
Controle le nb de fichiers de chaque catégorie et notifie.
|
|
Parcours la liste de notifications du projet et ajoute chaque
|
|
notification dans la feuille concerné du classeur
|
|
A défaut, une notification de la liste qui n'a pas de catégorie
|
|
avec sa propre feuille sera ajoutée à la première feuille (FRONT)
|
|
|
|
Enregistre le Visa dans le repertoire de Travail
|
|
Contraintes :
|
|
- le modele du VISA doit être NÉCESSAIREMENT dans le même
|
|
dossier que le script. TODO : traité l'exception si fichier non trouvé
|
|
- le modele du VISA NE doit PAS avoir eu de modification notable
|
|
dans son design ( emplacements des cellules utilisées pour
|
|
notifier, nom des feuilles, etc)
|
|
"""
|
|
|
|
print("\nvisa.remplir()")
|
|
|
|
|
|
|
|
# creation d'un workbook à partir d'un modele
|
|
classeur = xls.load_workbook(modele)
|
|
|
|
|
|
## definition personnalisé vers chaque feuille du classeur
|
|
FRONT = classeur[classeur.sheetnames[0]]
|
|
PDF = classeur[classeur.sheetnames[1]]
|
|
CSV = classeur[classeur.sheetnames[2]]
|
|
DWG = classeur[classeur.sheetnames[3]]
|
|
|
|
|
|
# Nom dossier
|
|
# Date de reception
|
|
# Date Visa
|
|
FRONT['C1'].value = f'Analyse : {projet.nom}\nDate de réception :\nDate visa : {projet.date}'
|
|
|
|
# Taille du dossier
|
|
taille = projet.taille
|
|
# Affichage adapté à la bonne unité
|
|
if taille < 1024 :
|
|
unite = "octets"
|
|
elif taille < 1024**2 :
|
|
unite = "Ko"
|
|
taille /= 1024
|
|
else :
|
|
unite = "Mo"
|
|
taille /= 1024**2
|
|
|
|
|
|
FRONT['C10'].value = f"Taille totale : {taille:.2f} {unite}."
|
|
|
|
|
|
# TODO: factoriser les instructions ci dessous (pas sur...)
|
|
|
|
|
|
|
|
### FRONT DWG
|
|
# Je ne peux pas controler automatiquement la projection du DWG (c'est un binaire illisible hors de AutoCAD)
|
|
# J'ajoute donc automatiquement la mention comme dans le script précedent.
|
|
FRONT['C3'].value = f"{projet.nb_dwgs} fichier(s) DWG présent(s).\nProjection de tous les fichiers DWG : RFG93-CC43 (EPSG:3943)."
|
|
|
|
# Controle le nb de fichiers DWG
|
|
if projet.nb_dwgs == 0:
|
|
projet.controles |= 2**4 # allume le bit 5ième bit
|
|
FRONT['C3'].value = "Pas de fichier DWG présent."
|
|
|
|
# Regarde si des fails ont été détectés sur les DWGs
|
|
fail = projet.controles & FAIL_DWG # operation logique avec le masque
|
|
# notifie en consequence
|
|
if fail :
|
|
FRONT['B3'].value = "FAIL"
|
|
else :
|
|
FRONT['B3'].value = "OK"
|
|
|
|
|
|
|
|
### FRONT PDF
|
|
FRONT['C4'].value = f"{projet.nb_shemas} fichier(s) PDF présent(s)."
|
|
|
|
# Controle le nb de fichiers PDF
|
|
if projet.nb_shemas == 0:
|
|
projet.controles |= 2**8 # allume le 9ième bit
|
|
FRONT['C4'] = "Pas de fichier PDF présent."
|
|
|
|
# Regarde si des fails ont été détectés sur les PDFs
|
|
fail = projet.controles & FAIL_PDF
|
|
# notifie en consequence
|
|
if fail :
|
|
FRONT['B4'].value = "FAIL"
|
|
else :
|
|
FRONT['B4'].value = "OK"
|
|
|
|
|
|
|
|
### FRONT CSV
|
|
FRONT['C5'].value = f"1 fichier(s) CSV présent(s).\n{projet.nb_points} point(s) en RFG93-CC43 (EPSG:3943)."
|
|
|
|
# Controle le nb de fichiers CSV
|
|
if projet.nb_csvs == 0:
|
|
projet.controles |= 2**0 # allume le 1er bit
|
|
FRONT['C5'].value = "Pas de fichier CSV présent."
|
|
|
|
# Regarde si des fails ont été détectés sur les CSVs
|
|
fail = projet.controles & FAIL_CSV
|
|
# notifie en consequence
|
|
if fail :
|
|
FRONT['B5'].value = "FAIL"
|
|
else :
|
|
FRONT['B5'].value = "OK"
|
|
|
|
|
|
|
|
# FRONT FICHE INFO TOPOLOGIE
|
|
FRONT['C6'].value = f"{projet.nb_releves} fiche(s) Info. présente(s)."
|
|
|
|
# Controle le nb de fichiers Fiche Topologique
|
|
if projet.nb_releves == 0:
|
|
projet.controles |= 2**12 # allume le 13ième bit
|
|
FRONT['C6'].value = "Pas de fiche d'Info. Topologie présente."
|
|
|
|
# Regarde si des fails ont été détectés sur les Fiches Topo
|
|
fail = projet.controles & FAIL_INFO
|
|
# notifie en consequence
|
|
if fail :
|
|
FRONT['B6'].value = "FAIL"
|
|
else :
|
|
FRONT['B6'].value = "OK"
|
|
|
|
|
|
|
|
|
|
# Notifier dans les autres Feuilles
|
|
|
|
# lignes en cours à remplir pour chaque feuille
|
|
# initialisé aux lignes où on va commencer à notifier
|
|
A = 2 # "B2" # Pour la feuille PDF
|
|
B = 2 # "B2" # Pour la feuille CSV
|
|
C = 2 # "B2" # Pour la feuille DWG
|
|
D = 12 # "C12" # Pour la feuille FRONT
|
|
|
|
cell = "" # cellule courante qui va être notifier
|
|
|
|
for notif in projet.notifs :
|
|
match notif.categorie :
|
|
case "PDF" :
|
|
cell = PDF["B"+str(A)]
|
|
A += 1
|
|
case "CSV" :
|
|
cell = CSV["B"+str(B)]
|
|
B += 1
|
|
case "DWG" :
|
|
cell = DWG["B"+ str(C)]
|
|
C += 1
|
|
case _:
|
|
cell = FRONT["C"+str(D)]
|
|
D += 1
|
|
|
|
cell.value = notif.texte
|
|
|
|
|
|
# Ici le VISA doit être correctement rempli
|
|
# on sauvegarde dans un fichier le classeur
|
|
classeur.save(f"Travail\\{projet.nom}_VISA.xlsx")
|
|
|
|
|
|
def purger_et_finir_programme(projet):
|
|
"""
|
|
Efface le dossier "Travail" si il existe puis termine le programme.
|
|
|
|
Cette fonction est utilisée quand des expections sont levées et
|
|
qu'elles nécessitent la fermeture prématurée du programme.
|
|
"""
|
|
print("\npurger_et_finir_programme()")
|
|
print("\nFIN DE PROGRAMME.\n")
|
|
# Ne fonctionne pas car des descripteurs de fichiers sont utilisés au moment de la demande
|
|
## shutil.rmtree(f"{projet.racine}\\{TRAVAIL}" , ignore_errors=True)
|
|
quit()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## NOTE : Pour traiter le cas des sous-dossiers lors du dézippage
|
|
# il vaut mieux que l'opérateur copie le fichier banbou.py dans chaque
|
|
# sous-dossiers puis l'execute.
|
|
## Donc :
|
|
# - Il est attendu que le fichier script se situe dans le dossier, au
|
|
# même niveau que les fichiers originaux.
|
|
# - Il est attendu que le modele du visa soit dans un autre dossier
|
|
# BIEN SPÉCIFIÉ (je vais remettre un chemin absolue "Desktop\Banbou" car suivant l'opérateur, le dézippage crée des sous-sous-dossiers)
|
|
# De plus, pour simplifier le dossier Travail se créera, dans le dossier
|
|
# ou se situe le script, aux coté des fichiers originaux
|
|
##TODO: Automatiser le cas des sous dossiers, avec un FOR each dossier FAIRE
|
|
## Et créer des dossiers Travail01, Travail02, etc
|
|
|
|
|
|
|
|
# Création entité projet et mise à jour de ses attributs
|
|
ce_Projet = _Projet()
|
|
|
|
enraciner(ce_Projet)
|
|
|
|
dater(ce_Projet)
|
|
|
|
nommer(ce_Projet)
|
|
# controle de la longueur du nom du projet
|
|
if len(ce_Projet.nom) >=46 :
|
|
print(f"\n{ce_Projet.nom} EST UN NOM DE DOSSIER TROP LONG (+ DE 46 CARACTÈRES). VEUILLEZ RACCOURCIR SON NOM.")
|
|
purger_et_finir_programme(ce_Projet)
|
|
|
|
# explorer le dossier Trouvé et fabriquer la liste des fichiers nécessaires
|
|
ce_Projet.lister_fichiers(ce_Projet.racine)
|
|
|
|
calculer_taille(ce_Projet)
|
|
|
|
# Ici le projet doit avoir toutes les données nécessaires pour fabriquer
|
|
# et remplir les dossiers attendus
|
|
preparer_dossier_travail(ce_Projet)
|
|
|
|
|
|
# il faut UN SEUL fichier CSV NOTE: a voir si ce controle est obligatoire
|
|
if ce_Projet.nb_csvs > 1:
|
|
print("\nAVERTISSEMENT : IL Y A PLUSIEURS FICHIERS CSV.")
|
|
print("VEUILLEZ NE GARDER QU'UN SEUL FICHIER CSV DANS LE DOSSIER ORIGINAL.")
|
|
purger_et_finir_programme(ce_Projet)
|
|
|
|
# On formatte le fichier CSV pour ArcGIS
|
|
for fichier in ce_Projet.fichiers:
|
|
if fichier.categorie in "CSV":
|
|
entree = ce_Projet.racine + "\\Travail\\Point_" + fichier.nom + "_IN" + ".csv"
|
|
sortie = ce_Projet.racine + "\\Travail\\Point_" + fichier.nom + "_IN" + ".csv"
|
|
formater_vers_ArcGIS(ce_Projet, entree, sortie)
|
|
|
|
|
|
|
|
# On controle les noms des fichiers copiés
|
|
controler_longueur_noms(ce_Projet)
|
|
|
|
|
|
# On fabrique le VISA
|
|
#modele = ce_Projet.racine + "\\VISA_BANBOU.xlsx"
|
|
remplir(MODELE, ce_Projet)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Fin de Programme Attendu
|
|
print("\nProgramme terminé correctement. ") |