mirror of
https://github.com/Alex38Lyon/Synthese-PSM_LARRA.git
synced 2026-06-01 13:59:13 +00:00
update pyCreateTh.py
This commit is contained in:
@@ -89,3 +89,41 @@
|
|||||||
2025-06-18 21:39:26,691 - INFO - ********************************************************************************************************************************************
|
2025-06-18 21:39:26,691 - INFO - ********************************************************************************************************************************************
|
||||||
2025-06-18 21:39:26,692 - ERROR - !!! file not yet supported
|
2025-06-18 21:39:26,692 - ERROR - !!! file not yet supported
|
||||||
2025-06-18 21:39:26,692 - ERROR - !!! There were 1 errors during 32.63 secondes, check the log file ~\..\pyCreateTh.log
|
2025-06-18 21:39:26,692 - ERROR - !!! There were 1 errors during 32.63 secondes, check the log file ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 08:27:09,067 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 08:27:09,068 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders
|
||||||
|
2025-06-19 08:27:09,068 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr
|
||||||
|
2025-06-19 08:27:09,068 - INFO - * Version : 2025.06.18
|
||||||
|
2025-06-19 08:27:09,068 - INFO - * Input file :
|
||||||
|
2025-06-19 08:27:09,068 - INFO - * Output file : ~\.
|
||||||
|
2025-06-19 08:27:09,069 - INFO - * Log file : ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 08:27:09,069 - INFO - *
|
||||||
|
2025-06-19 08:27:09,069 - INFO - *
|
||||||
|
2025-06-19 08:27:09,070 - INFO - *
|
||||||
|
2025-06-19 08:27:09,070 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 08:27:09,071 - ERROR - !!! file not yet supported
|
||||||
|
2025-06-19 08:27:09,071 - ERROR - !!! There were 1 errors during 3.02 secondes, check the log file ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 15:01:03,588 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 15:01:03,592 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders
|
||||||
|
2025-06-19 15:01:03,592 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr
|
||||||
|
2025-06-19 15:01:03,592 - INFO - * Version : 2025.06.18
|
||||||
|
2025-06-19 15:01:03,593 - INFO - * Input file :
|
||||||
|
2025-06-19 15:01:03,593 - INFO - * Output file : ~\.
|
||||||
|
2025-06-19 15:01:03,593 - INFO - * Log file : ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 15:01:03,593 - INFO - *
|
||||||
|
2025-06-19 15:01:03,594 - INFO - *
|
||||||
|
2025-06-19 15:01:03,594 - INFO - *
|
||||||
|
2025-06-19 15:01:03,594 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 15:01:03,595 - ERROR - !!! file not yet supported
|
||||||
|
2025-06-19 15:01:03,595 - ERROR - !!! There were 1 errors during 3.53 secondes, check the log file ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 23:34:59,337 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 23:34:59,341 - INFO - * Conversion Th, Dat, Mak files to Therion files and folders
|
||||||
|
2025-06-19 23:34:59,341 - INFO - * Script pyCreateTh by : alexandre.pont@yahoo.fr
|
||||||
|
2025-06-19 23:34:59,341 - INFO - * Version : 2025.06.18
|
||||||
|
2025-06-19 23:34:59,341 - INFO - * Input file :
|
||||||
|
2025-06-19 23:34:59,342 - INFO - * Output file : ~\.
|
||||||
|
2025-06-19 23:34:59,342 - INFO - * Log file : ~\..\pyCreateTh.log
|
||||||
|
2025-06-19 23:34:59,342 - INFO - *
|
||||||
|
2025-06-19 23:34:59,342 - INFO - *
|
||||||
|
2025-06-19 23:34:59,342 - INFO - *
|
||||||
|
2025-06-19 23:34:59,342 - INFO - ********************************************************************************************************************************************
|
||||||
|
2025-06-19 23:34:59,343 - ERROR - !!! file not yet supported
|
||||||
|
|||||||
+6
@@ -7,6 +7,7 @@
|
|||||||
"australiangeodeticdatum",
|
"australiangeodeticdatum",
|
||||||
"backclino",
|
"backclino",
|
||||||
"backcompass",
|
"backcompass",
|
||||||
|
"Backsights",
|
||||||
"beijing",
|
"beijing",
|
||||||
"cavename",
|
"cavename",
|
||||||
"clarke",
|
"clarke",
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
"drawnexemptre",
|
"drawnexemptre",
|
||||||
"drawnre",
|
"drawnre",
|
||||||
"ecart",
|
"ecart",
|
||||||
|
"ecarts",
|
||||||
"ENDC",
|
"ENDC",
|
||||||
"endlayout",
|
"endlayout",
|
||||||
"endscrap",
|
"endscrap",
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
"lenmatch",
|
"lenmatch",
|
||||||
"levelname",
|
"levelname",
|
||||||
"levelno",
|
"levelno",
|
||||||
|
"LRUD",
|
||||||
"migovec",
|
"migovec",
|
||||||
"NODRAW",
|
"NODRAW",
|
||||||
"northamerican",
|
"northamerican",
|
||||||
@@ -59,6 +62,9 @@
|
|||||||
"thconfig",
|
"thconfig",
|
||||||
"therion",
|
"therion",
|
||||||
"totdata",
|
"totdata",
|
||||||
|
"UUUUDDDDSSSB",
|
||||||
|
"UUUUDDDDSSSBL",
|
||||||
|
"UUUUDDDDSSSSSBL",
|
||||||
"wpage",
|
"wpage",
|
||||||
"XTHERION"
|
"XTHERION"
|
||||||
]
|
]
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,285 @@
|
|||||||
|
"""
|
||||||
|
#############################################################################################
|
||||||
|
general_fonctions.py for pyCreateTh.py
|
||||||
|
#############################################################################################
|
||||||
|
"""
|
||||||
|
import os, logging, sys, re, configparser
|
||||||
|
import Lib.global_data as global_data
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Couleurs ANSI par niveau de log
|
||||||
|
#################################################################################################
|
||||||
|
COLOR_CODES = {
|
||||||
|
logging.DEBUG: "\033[94m", # Bleu
|
||||||
|
logging.INFO: "\033[92m", # Vert
|
||||||
|
logging.WARNING: "\033[95m", # MAGENTA
|
||||||
|
logging.ERROR: "\033[91m", # Rouge
|
||||||
|
logging.CRITICAL: "\033[1;91m", # Rouge vif
|
||||||
|
}
|
||||||
|
RESET = "\033[0m"
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Codes de couleur ANSI
|
||||||
|
class Colors:
|
||||||
|
BLACK = '\033[90m'
|
||||||
|
RED = '\033[91m'
|
||||||
|
GREEN = '\033[92m'
|
||||||
|
YELLOW = '\033[93m'
|
||||||
|
BLUE = '\033[94m'
|
||||||
|
MAGENTA = '\033[95m'
|
||||||
|
CYAN = '\033[96m'
|
||||||
|
WHITE = '\033[97m'
|
||||||
|
|
||||||
|
ERROR = '\033[91m'
|
||||||
|
WARNING = '\033[95m'
|
||||||
|
HEADER = '\033[96m'
|
||||||
|
DEBUG = '\033[94m' # Bleu
|
||||||
|
INFO = '\033[92m' # Vert
|
||||||
|
CRITICAL = '\033[1;91m', # Rouge vif
|
||||||
|
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def safe_relpath(path):
|
||||||
|
"""
|
||||||
|
Renvoie un chemin relatif si possible, sinon un chemin partiel à partir du dossier de référence.
|
||||||
|
"""
|
||||||
|
|
||||||
|
abs_path = os.path.abspath(path)
|
||||||
|
ref_path = os.path.abspath(os.getcwd())
|
||||||
|
|
||||||
|
try:
|
||||||
|
valeur = "~\\" + os.path.relpath(path, ref_path)
|
||||||
|
return valeur
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
max_depth = 4 # Profondeur maximale pour tronquer le chemin
|
||||||
|
|
||||||
|
# Disques différents, afficher le chemin relatif partiel depuis la racine commune
|
||||||
|
path_parts = abs_path.split(os.sep)
|
||||||
|
ref_parts = ref_path.split(os.sep)
|
||||||
|
while path_parts and ref_parts and path_parts[0] == ref_parts[0]:
|
||||||
|
path_parts.pop(0)
|
||||||
|
ref_parts.pop(0)
|
||||||
|
result = os.path.join(*path_parts) if path_parts else os.path.basename(path)
|
||||||
|
|
||||||
|
# Si max_depth est défini, tronque le chemin
|
||||||
|
if max_depth is not None:
|
||||||
|
parts = result.split(os.sep)
|
||||||
|
if len(parts) > max_depth:
|
||||||
|
result = os.path.join("~\\" , *parts[-max_depth:])
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Coloration des messages d'aide d'arg #
|
||||||
|
#################################################################################################
|
||||||
|
def colored_help(parser):
|
||||||
|
"""
|
||||||
|
Affiche l'aide colorée pour les arguments de la ligne de commande.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parser (argparse.ArgumentParser): Le parseur d'arguments.
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Captures the help output
|
||||||
|
help_text = parser.format_help()
|
||||||
|
|
||||||
|
# Coloration des différentes parties
|
||||||
|
colored_help_text = help_text.replace(
|
||||||
|
'usage:', f'{Colors.ERROR}usage:{Colors.ENDC}'
|
||||||
|
).replace(
|
||||||
|
'options:', f'{Colors.GREEN}options:{Colors.ENDC}'
|
||||||
|
).replace('positional arguments:', f'{Colors.BLUE}positional arguments:{Colors.ENDC}'
|
||||||
|
).replace(', --help', f'{Colors.BLUE}, --help:{Colors.ENDC}'
|
||||||
|
).replace('elp:', f'{Colors.BLUE}elp{Colors.ENDC}')
|
||||||
|
|
||||||
|
# Surligner les arguments
|
||||||
|
for action in parser._actions:
|
||||||
|
if action.option_strings:
|
||||||
|
# Colorer les options (--xyz)
|
||||||
|
for opt in action.option_strings:
|
||||||
|
colored_help_text = colored_help_text.replace(opt, f'{Colors.BLUE}{opt}{Colors.ENDC}').replace('--help', f'{Colors.BLUE}--help:{Colors.ENDC}')
|
||||||
|
|
||||||
|
# Imprimer le texte coloré
|
||||||
|
print(colored_help_text)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def select_file_tk_window():
|
||||||
|
"""
|
||||||
|
Ouvre une boite de dialogue tkinter pour sélectionner un fichier.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Le chemin complet du fichier sélectionné.
|
||||||
|
"""
|
||||||
|
# Créer une instance de la fenêtre tkinter
|
||||||
|
root = tk.Tk()
|
||||||
|
|
||||||
|
# Cacher la fenêtre principale
|
||||||
|
root.withdraw()
|
||||||
|
|
||||||
|
# Afficher la boite de dialogue de sélection de fichier
|
||||||
|
file_path = filedialog.askopenfilename(
|
||||||
|
title="Select your file",
|
||||||
|
filetypes=[("MAK files", "*.mak"), ("Compatibles files", "*.th *.mak *.dat"), ("TH files", "*.th"), ("DAT files", "*.dat"), ("All files", "*.*")]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
return file_path # Retourner le chemin complet du fichier sélectionné
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def read_config(config_file):
|
||||||
|
"""
|
||||||
|
Lit le fichier de configuration et initialise les variables globales.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_file (str): Le chemin vers le fichier de configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Initialize the configparser to read .ini files
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(config_file, encoding="utf-8")
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Author' in config['Survey_Data']:
|
||||||
|
global_data.Author = config['Survey_Data']['Author']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Copyright1' in config['Survey_Data']:
|
||||||
|
global_data.Copyright = config['Survey_Data']['Copyright1'] + "\n" + config['Survey_Data']['Copyright2'] + "\n" + config['Survey_Data']['Copyright3'] + "\n"
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'Copyright_Short' in config['Survey_Data']:
|
||||||
|
global_data.CopyrightShort = config['Survey_Data']['Copyright_Short']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'map_comment' in config['Survey_Data']:
|
||||||
|
global_data.mapComment = config['Survey_Data']['map_comment']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'club' in config['Survey_Data']:
|
||||||
|
global_data.club = config['Survey_Data']['club']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'thanksto' in config['Survey_Data']:
|
||||||
|
global_data.thanksto = config['Survey_Data']['thanksto']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'datat' in config['Survey_Data']:
|
||||||
|
global_data.datat = config['Survey_Data']['datat']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'wpage' in config['Survey_Data']:
|
||||||
|
global_data.wpage = config['Survey_Data']['wpage']
|
||||||
|
|
||||||
|
if 'Survey_Data' in config and 'cs' in config['Survey_Data']:
|
||||||
|
global_data.cs = config['Survey_Data']['cs']
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'template_path' in config['Application_Data']:
|
||||||
|
global_data.templatePath = config['Application_Data']['template_path']
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'station_by_scrap' in config['Application_Data']:
|
||||||
|
global_data.stationByScrap = int(config['Application_Data']['station_by_scrap'])
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'final_therion_exe' in config['Application_Data']:
|
||||||
|
global_data.finalTherionExe = bool(config['Application_Data']['final_therion_exe'])
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'therion_path' in config['Application_Data']:
|
||||||
|
global_data.therionPath = config['Application_Data']['therion_path']
|
||||||
|
|
||||||
|
if 'Application_Data' in config and 'therion_path' in config['Application_Data']:
|
||||||
|
global_data.SurveyPrefixName = config['Application_Data']['survey_prefix_name']
|
||||||
|
|
||||||
|
if global_data.linesInTh2 == -1 :
|
||||||
|
if 'Application_Data' in config and 'shot_lines_in_th2_files' in config['Application_Data']:
|
||||||
|
linesInTh2 = 0 if config['Application_Data']['shot_lines_in_th2_files'] == "False" else 1
|
||||||
|
|
||||||
|
if global_data.stationNamesInTh2 == -1 :
|
||||||
|
if 'Application_Data' in config and 'station_name_in_th2_files' in config['Application_Data']:
|
||||||
|
global_data.stationNamesInTh2 = 0 if config['Application_Data']['station_name_in_th2_files'] == "False" else 1
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Supprime les codes ANSI (pour l'écriture dans les fichiers)
|
||||||
|
#################################################################################################
|
||||||
|
def strip_ansi_codes(text):
|
||||||
|
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
||||||
|
return ansi_escape.sub('', text)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Formatter pour la console avec couleurs
|
||||||
|
#################################################################################################
|
||||||
|
class ConsoleFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
color = COLOR_CODES.get(record.levelno, "")
|
||||||
|
message = super().format(record)
|
||||||
|
return f"{color}{message}{RESET}"
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Formatter pour le fichier avec "!!!" sur les erreurs
|
||||||
|
#################################################################################################
|
||||||
|
class FileFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
clean_msg = strip_ansi_codes(record.getMessage())
|
||||||
|
prefix = "!!! " if record.levelno >= logging.ERROR else ""
|
||||||
|
record_copy = logging.LogRecord(
|
||||||
|
name=record.name,
|
||||||
|
level=record.levelno,
|
||||||
|
pathname=record.pathname,
|
||||||
|
lineno=record.lineno,
|
||||||
|
msg=f"{prefix}{clean_msg}",
|
||||||
|
args=(),
|
||||||
|
exc_info=record.exc_info,
|
||||||
|
func=record.funcName,
|
||||||
|
sinfo=record.stack_info
|
||||||
|
)
|
||||||
|
return super().format(record_copy)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
# Fonction de configuration du logger
|
||||||
|
#################################################################################################
|
||||||
|
def setup_logger(logfile="app.log", debug_log=False):
|
||||||
|
logger = logging.getLogger("Logger")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
logger.handlers.clear()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
min_level = logging.DEBUG if debug_log else logging.INFO
|
||||||
|
|
||||||
|
|
||||||
|
# Console stderr handler — affichage à l'écran avec couleurs
|
||||||
|
stderr_handler = logging.StreamHandler(sys.stderr)
|
||||||
|
stderr_handler.setLevel(min_level)
|
||||||
|
stderr_formatter = ConsoleFormatter("%(levelname)s: %(message)s") # <-- Ta classe personnalisée
|
||||||
|
stderr_handler.setFormatter(stderr_formatter)
|
||||||
|
logger.addHandler(stderr_handler)
|
||||||
|
|
||||||
|
# File handler — fichier de log
|
||||||
|
file_handler = logging.FileHandler(logfile, encoding="utf-8")
|
||||||
|
file_handler.setLevel(min_level)
|
||||||
|
file_formatter = FileFormatter("%(asctime)s - %(levelname)s - %(message)s") # <-- Ta classe personnalisée
|
||||||
|
file_handler.setFormatter(file_formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
def release_log_file(logger):
|
||||||
|
handlers = logger.handlers[:]
|
||||||
|
for handler in handlers:
|
||||||
|
if isinstance(handler, logging.FileHandler):
|
||||||
|
handler.close()
|
||||||
|
logger.removeHandler(handler)
|
||||||
@@ -7,9 +7,30 @@ global_data.py for pyCreateTh.py
|
|||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
|
||||||
error_count = 0 # Compteur d'erreurs
|
error_count = 0 # Compteur d'erreurs
|
||||||
|
|
||||||
|
## [Survey_Data] default values
|
||||||
|
Author = "Created by pyCreateTh.py"
|
||||||
|
Copyright = "# global_data.Copyright (C) pyCreateTh.py"
|
||||||
|
CopyrightShort = "Licence (C) pyCreateTh.py"
|
||||||
|
mapComment = "Created by pyCreateTh.py"
|
||||||
|
cs = "UTM30"
|
||||||
|
club = "Therion"
|
||||||
|
thanksto = "Therion"
|
||||||
|
datat = "https://therion.speleo.sk/"
|
||||||
|
wpage = "https://therion.speleo.sk/"
|
||||||
|
|
||||||
|
## [Application_data] default values
|
||||||
|
templatePath = "./Template"
|
||||||
|
stationByScrap = 20
|
||||||
|
finalTherion_exe = True
|
||||||
|
therionPath = "C:/Therion/therion.exe"
|
||||||
|
SurveyPrefixName = f"Survey_"
|
||||||
|
linesInTh2 = -1
|
||||||
|
stationNamesInTh2 = -1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
thFileDat = """
|
thFileDat = """
|
||||||
encoding utf-8
|
encoding utf-8
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
"""
|
|
||||||
#############################################################################################
|
|
||||||
logger_config.py for pyCreateTh.py
|
|
||||||
#############################################################################################
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Couleurs ANSI par niveau de log
|
|
||||||
#################################################################################################
|
|
||||||
COLOR_CODES = {
|
|
||||||
logging.DEBUG: "\033[94m", # Bleu
|
|
||||||
logging.INFO: "\033[92m", # Vert
|
|
||||||
logging.WARNING: "\033[95m",
|
|
||||||
logging.ERROR: "\033[91m", # Rouge
|
|
||||||
logging.CRITICAL: "\033[1;91m", # Rouge vif
|
|
||||||
}
|
|
||||||
RESET = "\033[0m"
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Supprime les codes ANSI (pour l'écriture dans les fichiers)
|
|
||||||
#################################################################################################
|
|
||||||
def strip_ansi_codes(text):
|
|
||||||
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
|
||||||
return ansi_escape.sub('', text)
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Formatter pour la console avec couleurs
|
|
||||||
#################################################################################################
|
|
||||||
class ConsoleFormatter(logging.Formatter):
|
|
||||||
def format(self, record):
|
|
||||||
color = COLOR_CODES.get(record.levelno, "")
|
|
||||||
message = super().format(record)
|
|
||||||
return f"{color}{message}{RESET}"
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Formatter pour le fichier avec "!!!" sur les erreurs
|
|
||||||
#################################################################################################
|
|
||||||
class FileFormatter(logging.Formatter):
|
|
||||||
def format(self, record):
|
|
||||||
clean_msg = strip_ansi_codes(record.getMessage())
|
|
||||||
prefix = "!!! " if record.levelno >= logging.ERROR else ""
|
|
||||||
record_copy = logging.LogRecord(
|
|
||||||
name=record.name,
|
|
||||||
level=record.levelno,
|
|
||||||
pathname=record.pathname,
|
|
||||||
lineno=record.lineno,
|
|
||||||
msg=f"{prefix}{clean_msg}",
|
|
||||||
args=(),
|
|
||||||
exc_info=record.exc_info,
|
|
||||||
func=record.funcName,
|
|
||||||
sinfo=record.stack_info
|
|
||||||
)
|
|
||||||
return super().format(record_copy)
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Fonction de configuration du logger
|
|
||||||
#################################################################################################
|
|
||||||
def setup_logger(logfile="app.log", debug_log=False):
|
|
||||||
logger = logging.getLogger("Logger")
|
|
||||||
logger.setLevel(logging.DEBUG)
|
|
||||||
logger.handlers.clear()
|
|
||||||
|
|
||||||
min_level = logging.DEBUG if debug_log else logging.INFO
|
|
||||||
|
|
||||||
# Console handler
|
|
||||||
console_handler = logging.StreamHandler(sys.stdout)
|
|
||||||
console_handler.setLevel(min_level)
|
|
||||||
console_formatter = ConsoleFormatter("%(levelname)s: %(message)s")
|
|
||||||
console_handler.setFormatter(console_formatter)
|
|
||||||
logger.addHandler(console_handler)
|
|
||||||
|
|
||||||
# File handler
|
|
||||||
file_handler = logging.FileHandler(logfile, encoding="utf-8")
|
|
||||||
file_handler.setLevel(min_level)
|
|
||||||
file_formatter = FileFormatter("%(asctime)s - %(levelname)s - %(message)s")
|
|
||||||
file_handler.setFormatter(file_formatter)
|
|
||||||
logger.addHandler(file_handler)
|
|
||||||
|
|
||||||
return logger
|
|
||||||
@@ -4,111 +4,20 @@ therion.py for pyCreateTh.py
|
|||||||
#############################################################################################
|
#############################################################################################
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tempfile
|
import tempfile, shutil, os, re, logging, threading, subprocess
|
||||||
import shutil
|
|
||||||
import os
|
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
import logging
|
|
||||||
import threading
|
|
||||||
import Lib.global_data as global_data
|
import Lib.global_data as global_data
|
||||||
|
from Lib.general_fonctions import Colors, safe_relpath
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger("Logger")
|
log = logging.getLogger("Logger")
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Codes de couleur ANSI
|
|
||||||
class Colors:
|
|
||||||
BLACK = '\033[90m'
|
|
||||||
RED = '\033[91m'
|
|
||||||
GREEN = '\033[92m'
|
|
||||||
YELLOW = '\033[93m'
|
|
||||||
BLUE = '\033[94m'
|
|
||||||
MAGENTA = '\033[95m'
|
|
||||||
CYAN = '\033[96m'
|
|
||||||
WHITE = '\033[97m'
|
|
||||||
|
|
||||||
ERROR = '\033[91m'
|
|
||||||
WARNING = '\033[95m'
|
|
||||||
HEADER = '\033[96m'
|
|
||||||
DEBUG = '\033[94m' # Bleu
|
|
||||||
INFO = '\033[92m' # Vert
|
|
||||||
CRITICAL = '\033[1;91m', # Rouge vif
|
|
||||||
|
|
||||||
ENDC = '\033[0m'
|
|
||||||
BOLD = '\033[1m'
|
|
||||||
UNDERLINE = '\033[4m'
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
def safe_relpath(path):
|
|
||||||
"""
|
|
||||||
Renvoie un chemin relatif si possible, sinon un chemin partiel à partir du dossier de référence.
|
|
||||||
"""
|
|
||||||
|
|
||||||
abs_path = os.path.abspath(path)
|
|
||||||
ref_path = os.path.abspath(os.getcwd())
|
|
||||||
|
|
||||||
try:
|
|
||||||
valeur = "~\\" + os.path.relpath(path, ref_path)
|
|
||||||
return valeur
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
max_depth = 4 # Profondeur maximale pour tronquer le chemin
|
|
||||||
|
|
||||||
# Disques différents, afficher le chemin relatif partiel depuis la racine commune
|
|
||||||
path_parts = abs_path.split(os.sep)
|
|
||||||
ref_parts = ref_path.split(os.sep)
|
|
||||||
while path_parts and ref_parts and path_parts[0] == ref_parts[0]:
|
|
||||||
path_parts.pop(0)
|
|
||||||
ref_parts.pop(0)
|
|
||||||
result = os.path.join(*path_parts) if path_parts else os.path.basename(path)
|
|
||||||
|
|
||||||
# Si max_depth est défini, tronque le chemin
|
|
||||||
if max_depth is not None:
|
|
||||||
parts = result.split(os.sep)
|
|
||||||
if len(parts) > max_depth:
|
|
||||||
result = os.path.join("~\\" , *parts[-max_depth:])
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
|
||||||
# Compilation Therion 'Template' (version avec blocage) #
|
|
||||||
#################################################################################################
|
|
||||||
def compile_templateOld(template, template_args, **kwargs):
|
|
||||||
|
|
||||||
try :
|
|
||||||
logfile = ""
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
|
||||||
config = template.format(**template_args, tmpdir=tmpdir.replace("\\", "/"))
|
|
||||||
|
|
||||||
log.debug(f"{config}\n")
|
|
||||||
|
|
||||||
config_file = join(tmpdir, "config.thconfig")
|
|
||||||
log_file = join(tmpdir, "log.log")
|
|
||||||
therion_path = kwargs["therion_path"] if "therion_path" in kwargs else "therion"
|
|
||||||
with open(config_file, mode="w+", encoding="utf-8") as tmp:
|
|
||||||
with open(log_file, mode="w+") as tmp2:
|
|
||||||
tmp.write(config)
|
|
||||||
tmp.flush()
|
|
||||||
subprocess.check_output('''"{}" "{}" -l "{}"'''.format(therion_path, config_file, log_file), shell=True, )
|
|
||||||
tmp2.flush()
|
|
||||||
logfile = tmp2.read()
|
|
||||||
if kwargs["cleanup"]:
|
|
||||||
shutil.rmtree(tmpdir)
|
|
||||||
log.debug("\n" )
|
|
||||||
return logfile, tmpdir
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"Therion template compilation error: {Colors.ENDC}{e}")
|
|
||||||
global_data.error_count += 1
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
# Compilation Therion 'Template' (version sans blocage) #
|
# Compilation Therion 'Template' (version sans blocage) #
|
||||||
# Compiler une configuration générée dynamiquement à partir d'un template texte. #
|
# Compiler une configuration générée dynamiquement à partir d'un template texte. #
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
def compile_template(template, template_args, **kwargs):
|
def compile_template(template, template_args, totReadMeError = "", **kwargs ):
|
||||||
logfile = ""
|
logfile = ""
|
||||||
tmpdir = None
|
tmpdir = None
|
||||||
try:
|
try:
|
||||||
@@ -147,23 +56,26 @@ def compile_template(template, template_args, **kwargs):
|
|||||||
# Analyse du code retour
|
# Analyse du code retour
|
||||||
if result.returncode != 0 or "press any key" in result.stdout.lower():
|
if result.returncode != 0 or "press any key" in result.stdout.lower():
|
||||||
log.error(f"Therion compilation failed with return code: {Colors.ENDC}{result.returncode}\n{Colors.WHITE}{result.stdout}")
|
log.error(f"Therion compilation failed with return code: {Colors.ENDC}{result.returncode}\n{Colors.WHITE}{result.stdout}")
|
||||||
|
totReadMeError += f"\tTherion compilation failed with return code: {result.returncode}\n"
|
||||||
global_data.error_count += 1
|
global_data.error_count += 1
|
||||||
return "Therion error", tmpdir
|
return "Therion error", tmpdir, totReadMeError
|
||||||
|
|
||||||
stat = get_stats_from_log(logfile)
|
stat = get_stats_from_log(logfile)
|
||||||
|
|
||||||
log.info(f"Therion compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m")
|
log.info(f"Therion compilation successful, length: {Colors.ENDC}{stat["length"]}m{Colors.INFO}, depth: {Colors.ENDC}{stat["depth"]}m")
|
||||||
return logfile, tmpdir
|
return logfile, tmpdir, totReadMeError
|
||||||
|
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
log.error(f"Therion process timed out and was terminated: {Colors.ENDC}{logfile}")
|
log.error(f"Therion process timed out and was terminated: {Colors.ENDC}{logfile}")
|
||||||
|
totReadMeError += f"\tTherion process timed out and was terminated\n"
|
||||||
global_data.error_count += 1
|
global_data.error_count += 1
|
||||||
return "Therion error", tmpdir
|
return "Therion error", tmpdir, totReadMeError
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Therion template compilation error: {Colors.ENDC}{e}")
|
log.error(f"Therion template compilation error: {Colors.ENDC}{e}")
|
||||||
|
totReadMeError += f"\tTherion template compilation error: {e}\n"
|
||||||
global_data.error_count += 1
|
global_data.error_count += 1
|
||||||
return "Therion error", tmpdir
|
return "Therion error", tmpdir, totReadMeError
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if kwargs.get("cleanup", True) and tmpdir:
|
if kwargs.get("cleanup", True) and tmpdir:
|
||||||
@@ -176,8 +88,7 @@ def compile_template(template, template_args, **kwargs):
|
|||||||
#################################################################################################
|
#################################################################################################
|
||||||
# Compilation Therion (version sans blocage) #
|
# Compilation Therion (version sans blocage) #
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
def compile_file(filename, **kwargs):
|
def compile_fileOLd(filename, **kwargs):
|
||||||
|
|
||||||
tmpdir = os.path.dirname(filename)
|
tmpdir = os.path.dirname(filename)
|
||||||
log_file = join(tmpdir, "therion.log").replace("\\", "/")
|
log_file = join(tmpdir, "therion.log").replace("\\", "/")
|
||||||
therion_path = kwargs.get("therion_path", "therion")
|
therion_path = kwargs.get("therion_path", "therion")
|
||||||
@@ -240,6 +151,70 @@ def compile_file(filename, **kwargs):
|
|||||||
global_data.error_count += 1
|
global_data.error_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
def compile_file(filename, **kwargs):
|
||||||
|
tmpdir = os.path.dirname(filename)
|
||||||
|
log_file = join(tmpdir, "therion.log").replace("\\", "/")
|
||||||
|
therion_path = kwargs.get("therion_path", "therion")
|
||||||
|
timeout = kwargs.get("timeout", 60)
|
||||||
|
|
||||||
|
log.info(f"Start therion compilation file: {Colors.ENDC}{safe_relpath(filename)}")
|
||||||
|
|
||||||
|
def run():
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[therion_path, filename, "-l", log_file],
|
||||||
|
cwd=tmpdir,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
universal_newlines=True,
|
||||||
|
bufsize=1
|
||||||
|
)
|
||||||
|
|
||||||
|
def read_output(proc):
|
||||||
|
try:
|
||||||
|
for line in proc.stdout:
|
||||||
|
line = line.rstrip()
|
||||||
|
lower_line = line.lower()
|
||||||
|
if "average loop error" in lower_line:
|
||||||
|
log.warning(f"[Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
elif "error" in lower_line:
|
||||||
|
log.error(f"[Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
elif "warning" in lower_line:
|
||||||
|
log.warning(f"[Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
else:
|
||||||
|
log.debug(f"[Therion_Compile] {Colors.ENDC}{line}")
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(f"Reading Therion output: {Colors.ENDC}{e}")
|
||||||
|
|
||||||
|
output_thread = threading.Thread(target=read_output, args=(process,))
|
||||||
|
output_thread.start()
|
||||||
|
|
||||||
|
output_thread.join(timeout)
|
||||||
|
if output_thread.is_alive():
|
||||||
|
log.error(f"Therion compilation timed out after {Colors.ENDC}{timeout}{Colors.ERROR} seconds. Killing process...")
|
||||||
|
global_data.error_count += 1
|
||||||
|
process.kill()
|
||||||
|
|
||||||
|
output_thread.join() # Toujours attendre proprement
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
if process.returncode != 0:
|
||||||
|
log.error(f"Therion returned error code {Colors.ENDC}{process.returncode}")
|
||||||
|
global_data.error_count += 1
|
||||||
|
else:
|
||||||
|
log.info(f"Therion file: {Colors.ENDC}{safe_relpath(filename)}{Colors.GREEN} compilation succeeded")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Therion file: {Colors.ENDC}{safe_relpath(filename)}{Colors.ERROR} compilation error: {Colors.ENDC}{e}")
|
||||||
|
global_data.error_count += 1
|
||||||
|
|
||||||
|
# Lancer le thread principal pour cette compilation et le retourner
|
||||||
|
thread = threading.Thread(target=run)
|
||||||
|
thread.start()
|
||||||
|
return thread
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
def compile_file_th(filepath, **kwargs):
|
def compile_file_th(filepath, **kwargs):
|
||||||
template = """source {filepath}
|
template = """source {filepath}
|
||||||
@@ -248,15 +223,18 @@ def compile_file_th(filepath, **kwargs):
|
|||||||
endlayout
|
endlayout
|
||||||
"""
|
"""
|
||||||
template_args = {"filepath": filepath}
|
template_args = {"filepath": filepath}
|
||||||
logs, _ = compile_template(template, template_args, cleanup=True, **kwargs)
|
logs, _, = compile_template(template, template_args, cleanup=True, **kwargs)
|
||||||
return logs
|
return logs
|
||||||
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
# Attention fonctionne pour la version therion en français ! à voir pour les autres langues
|
# Attention fonctionne pour la version therion en français ! à voir pour les autres langues
|
||||||
lengthre = re.compile(r".*Longueur totale de la topographie = \s*(\S+)m")
|
lengthre = re.compile(r".*Longueur totale de la topographie = \s*(\S+)m")
|
||||||
depthre = re.compile(r".*Longueur totale verticale =\s*(\S+)m")
|
depthre = re.compile(r".*Longueur totale verticale =\s*(\S+)m")
|
||||||
|
|
||||||
def get_stats_from_log(log):
|
def get_stats_from_log(log):
|
||||||
|
|
||||||
|
|
||||||
lenmatch = lengthre.findall(log)
|
lenmatch = lengthre.findall(log)
|
||||||
depmatch = depthre.findall(log)
|
depmatch = depthre.findall(log)
|
||||||
if len(lenmatch) == 1 and len(depmatch) == 1:
|
if len(lenmatch) == 1 and len(depmatch) == 1:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# Fix point list
|
# Fix point list
|
||||||
{fixPointList}
|
{fixPointList}
|
||||||
|
|
||||||
# Survey list :
|
# Survey / file list :
|
||||||
{readMeList}
|
{readMeList}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ endlayout
|
|||||||
# export model -fmt kml -o Outputs/{fileName}-model.kml -enable all
|
# export model -fmt kml -o Outputs/{fileName}-model.kml -enable all
|
||||||
# export model -enable all -o Outputs/{fileName}-3D.kml
|
# export model -enable all -o Outputs/{fileName}-3D.kml
|
||||||
# export cave-list -location on -o Outputs/{fileName}-Cave-list.html
|
# export cave-list -location on -o Outputs/{fileName}-Cave-list.html
|
||||||
# export survey-list -location on -o Outputs/{fileName}-Surveys.html
|
export survey-list -location on -o Outputs/{fileName}-Surveys.html
|
||||||
# export database -fmt sql -o Outputs/{fileName}-database.sql
|
# export database -fmt sql -o Outputs/{fileName}-database.sql
|
||||||
# export continuation-list -o Outputs/{fileName}-Continuations.html
|
# export continuation-list -o Outputs/{fileName}-Continuations.html
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ template_path = ./template
|
|||||||
station_by_scrap = 30
|
station_by_scrap = 30
|
||||||
final_therion_exe = True
|
final_therion_exe = True
|
||||||
therion_path = C:\Program Files\Therion\therion.exe
|
therion_path = C:\Program Files\Therion\therion.exe
|
||||||
shot_lines_in_th2_files = False
|
survey_prefix_name = Explo_
|
||||||
|
shot_lines_in_th2_files = True
|
||||||
station_name_in_th2_files = True
|
station_name_in_th2_files = True
|
||||||
|
|||||||
+544
-612
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user