/
Flipper
/
Marginal
Обзор
Документация
Войти
/
Flipper
/
Marginal
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
master
src/Backbone.py
346 строк
11 KB
Alex
Marginal v1.0.0 RELEASE
11 янв 2026, 18:02
11 янв 2026, 18:02
5e1eff8
Код
Авторство
О чём код?
from FileManager import FileManager from Processor import Processor from Validator import Validator from Logger import Logger from UIManager import UIManager from ExceptionManager import ExceptionManager from ConfigManager import ConfigManager from Canvas import Canvas from Locksmith import PassKeeper from Enviformer import Envformer from Translator import AppTranslator class Backbone: """ Central application coordinator. Responsible for initializing, owning, and wiring together all major subsystems of the application. Acts as the primary interface between UI actions and backend logic. """ def __init__(self): """ Initialize all core subsystems and establish cross-dependencies. """ self.bootComplete = False self.envFormer = Envformer() self.translator = AppTranslator("marginal") self.logger = Logger(self) self._dumpStats() self.translator.setLogger(self.logger) self.validator = Validator(self) self.configManager = ConfigManager(backbone=self) self.fileManager = FileManager(self) self.processor = Processor(self) self.uiManager = UIManager(self) self.exceptionManager = ExceptionManager(self) self.canvas = Canvas(self) self.passKeeper = PassKeeper(self) self.enableGraphing = self.getConfig("graphOptions")["enabled"] self.allowStyleOverwrite = self.getConfig("graphOptions")["allowStyleOverwrite"] self.bootComplete = True def runApp(self): """ Start the application UI loop and persist configuration on exit. """ self.uiManager.run() self.configManager.saveConfig() def runCalculation(self,excelPath: str,profilePath: str,outputPath: str,exportMode: str, createCalcLog: bool,filename: str = None,openOnFinish: bool = False): """ Execute a full calculation pipeline based on a profile definition. Args: excelPath (str): Path to the input Excel file. profilePath (str): Path to the calculation profile. outputPath (str): Directory where results will be exported. exportMode (str): Output format / export strategy. createCalcLog (bool): Enable per-calculation logging. filename (str | None): Optional output filename override. openOnFinish (bool): Open output directory after completion. Returns: bool -> True if calculation completed successfully, False otherwise. """ if not self._checkParams(excelPath, profilePath, outputPath, exportMode): return False try: self.logger.log("System", "Running calculation for {path}", path=profilePath) profile = self.fileManager.loadProfile(profilePath) self.logger.customLog("->Validating profile file...", translate=True) if not self.validator.validateProfile( profile, self.configManager.getMeta("compatibility")["min_profile"] ): self.logger.customLog("->Profile validation FAILED.", translate=True) return False filename = self.fileManager.generateFileName(filename) self.logger.customLog("->Reading input data...", translate=True) data = self.fileManager.readExcelData( excelPath, profile["inputs"] ) # Inject constant values directly into calculation input data if "constants" in profile: for constName, constData in profile["constants"].items(): data[constName] = constData.get("value") if createCalcLog: self.logger.startCalcLog( filename, outputPath, profile=profile, input=data ) # Perform calculations only if explicitly defined if "calculations" in profile and profile["calculations"]: self.logger.customLog("->Performing calculations...", translate=True) results = self.processor.process( profile, data, createCalcLog ) else: self.logger.customLog( "->No calculations defined, using input data only.", translate=True ) results = {} self.logger.closeCalcLog() # Backward compatibility for legacy text headers oldStyleTextHeaders = profile.get("textHeaders", None) # Write outputs only if defined in profile if "outputs" in profile and profile["outputs"]: self.logger.customLog("->Writing outputs...") self.fileManager.writeOutputs( profile["outputs"], results, outputPath, exportMode, filename, openOnFinish, oldStyleTextHeaders ) else: self.logger.customLog( "->No outputs defined, skipping export.", translate=True ) # Generate plots if enabled and defined if "plots" in profile and self.enableGraphing: self.logger.customLog("->Initializing graph creation...") for plotName, plotConfig in profile["plots"].items(): fig = self.canvas.createPlot( plotConfig, data, results, plotName, useThemeStyle=True, allowStyleOverwrite=self.allowStyleOverwrite ) if fig: graphFileName = f"{filename}_{plotName}_GRAPH" plotPath = self.fileManager.saveGraph( fig, outputPath, graphFileName ) if plotPath: self.logger.customLog( "->Plot generated: {path}", path=plotPath.replace("\\", "/") ) self.canvas.closeFig(fig) return True except Exception as e: self.logger.log("System","Failed to complete calculations: {e}",hideInConsole=True,e=e) return False def closeLogs(self): """ Close the main application log file. """ self.logger.closeLog() def getConfig(self, key=None): """ Retrieve application configuration. Args: key (str | None): Optional configuration key. Returns: Any -> Full config or specific config entry. """ return self.configManager.getConfig(key) def getMeta(self, key=None): """ Retrieve application metadata. Args: key (str | None): Optional metadata key. Returns: Any -> Full metadata or specific entry. """ return self.configManager.getMeta(key) def refreshConfigs(self): """ Reload configuration-dependent runtime settings. """ if not self.bootComplete: return self.enableGraphing = self.getConfig("graphOptions")["enabled"] self.allowStyleOverwrite = self.getConfig("graphOptions")["allowStyleOverwrite"] self.canvas.loadStyle(log=True) self.fileManager.useConfig() self.uiManager.refreshConfig() self.passKeeper.useConfig() def getAccess(self) -> bool: """ Request user access via password verification. Returns: bool -> True if access granted, False otherwise. """ result = self.passKeeper.getAccess() if result[0] is True: if result[1]: self.logger.log("Locksmith", "Access granted.") return True if result[0] is False: if result[1]: self.logger.log("Locksmith", "Incorrect password, access denied.") return False return False def _checkParams(self,excelPath: str,profilePath: str,outputPath: str,exportMode: str) -> bool: """ Validate required parameters before starting a calculation. Returns: bool -> True if all parameters are valid. """ if not excelPath: self.logger.log( "System", "Failed to start calculations:\n->Input data filepath is not set." ) return False if not profilePath: self.logger.log( "System", "Failed to start calculations:\n->Profile filepath is not set." ) return False if not outputPath: self.logger.log( "System", "Failed to start calculations:\n->Export path is not set." ) return False if not exportMode: self.logger.log( "System", "Failed to start calculations:\n->Export mode is not set." ) return False return True def getHash(self, input: str) -> str: """ Generate a password hash. Args: input (str): Raw input string. Returns: str -> Hashed value. """ return self.passKeeper.getHash(input) def getNewPass(self): """ Trigger password change workflow. """ return self.passKeeper.setNewPass() def checkDirs(self,dirs: list,createMissing: bool = False,func: callable = None): """ Validate required directories. Args: dirs (list): Directories to validate. createMissing (bool): Create missing directories if True. func (callable | None): Optional progress callback. """ return self.envFormer.validateDirs(dirs, createMissing, func) def openSettings(self): """ Open the application settings dialog. """ self.uiManager.openSettings() def _dumpStats(self): """ Log environment initialization results. """ message = ( "Environment check complete:\n->" + ";\n->".join( f"{key[:1].upper() + key[1:]}: {value}" for key, value in self.envFormer.initCheckResults.items() ) ) self.logger.log("Enviformer", message, True) class LocksmithBB: """ Lightweight bootstrap container for locked app logic. """ def __init__(self): """ Initialize translator and validator for early locked app workflows. """ self.translator = AppTranslator("marginal") self.logger = None self.validator = Validator(None)