/
Flipper
/
Marginal
Обзор
Документация
Войти
/
Flipper
/
Marginal
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
master
src/Validator.py
226 строк
9 KB
Alex
Bug fixes.
12 янв 2026, 13:17
12 янв 2026, 13:17
e907759
Код
Авторство
О чём код?
class Validator: """ Validates application profiles, version compatibility, and filenames. Handles structural validation and generates warnings for optional field issues. """ # Required fields for a valid profile profilesRequiredFields = ["profileName", "metadata", "inputs"] # Optional fields that may be present in a profile profilesOptionalFields = ["calculations", "outputs"] def __init__(self, backbone=None): """ Initialize Validator with optional backbone for logging. Args: backbone (Backbone, optional): Central application controller for logging. """ if backbone: self.logger = backbone.logger self.warnings = [] def validateProfile(self, profile, minVersion: str = None) -> bool: """ Validate the structure and content of a profile dictionary. Args: profile (dict): Profile dictionary to validate. minVersion (str, optional): Minimum compatible version string (e.g., "1.2.3"). Returns: bool -> True if profile is valid, False otherwise. Note: Missing optional fields generate warnings but don't fail validation. Invalid required fields or structures cause validation failure. """ self.warnings.clear() # Check that all required fields are present for field in self.profilesRequiredFields: if field not in profile: if self.logger: self.logger.log( "Validator", f"Profile missing required field: {field}", True, field=field ) return False # Validate metadata structure if not isinstance(profile["metadata"], dict): if self.logger: self.logger.log("Validator", "Invalid 'metadata' structure.", True) return False # Validate version field in metadata if ( profile["metadata"].get("version", None) is None or not isinstance(profile["metadata"]["version"], str) ): if self.logger: self.logger.log( "Validator", "Missing or invalid 'metadata' field: 'version'.", True ) return False # Check version compatibility if minimum version specified if minVersion and not self.checkCompatibility( profile["metadata"]["version"], minVersion ): if self.logger: self.logger.log( "Validator", f"Incompatible profile version. Must be above: v{minVersion}.", True, minVersion=minVersion ) return False # Validate inputs structure if not isinstance(profile["inputs"], dict): if self.logger: self.logger.log("Validator", "Invalid 'inputs' structure.", True) return False # Warn about missing optional fields (non-fatal) for field in self.profilesOptionalFields: if field not in profile: warningMsg = f"Optional field '{field}' not found in profile" self.warnings.append(warningMsg) # Validate calculations if present if "calculations" in profile: if not isinstance(profile["calculations"], list): if self.logger: self.logger.log("Validator", "Invalid 'calculations' structure.", True) return False # Validate each calculation entry for calc in profile["calculations"]: if "name" not in calc or "operation" not in calc: if self.logger: self.logger.log( "Validator", "Calculation missing 'name' or 'operation'.", True ) return False # Validate outputs if present if "outputs" in profile: if not isinstance(profile["outputs"], dict): if self.logger: self.logger.log("Validator", "Invalid 'outputs' structure.", True) return False # Validate each output entry for key, outputInfo in profile["outputs"].items(): # Check for textHeader structure if present if "textHeader" in outputInfo: textHeader = outputInfo["textHeader"] if not isinstance(textHeader, dict): if self.logger: self.logger.log( "Validator", f"Invalid textHeader structure for output '{key}'.", True ) return False # textHeader must have at least placement and text if "placement" not in textHeader or "text" not in textHeader: if self.logger: self.logger.log( "Validator", f"textHeader missing required fields for output '{key}'.", True ) return False # Optional bold field should be boolean if present if "bold" in textHeader and not isinstance(textHeader["bold"], bool): if self.logger: self.logger.log( "Validator", f"textHeader 'bold' field must be boolean for output '{key}'.", True ) return False # Log any warnings that were collected if self.warnings and self.logger: self.logger.log( "Validator", "Several potential issues found during the validation:", True ) for warning in self.warnings: message = f"->[NOTICE]: {warning}" self.logger.customLog(message, translate=False, hideInConsole=True) # Log successful validation if self.logger: self.logger.log( "Validator", f"Profile '{profile['profileName']}' validated successfully.", True, profileName=profile['profileName'] ) return True def checkCompatibility(self, version: str, control: str) -> bool: """ Check if a version string meets or exceeds a minimum control version. Args: version (str): Version string to check (e.g., "2.1.0"). control (str): Minimum required version (e.g., "2.0.0"). Returns: bool -> True if version >= control, False otherwise. Note: Uses semantic version comparison (major.minor.patch). Assumes version numbers are integers separated by dots. """ versionParts = version.split('.') controlParts = control.split('.') minLength = min(len(versionParts), len(controlParts)) # Compare each version component from left to right for i in range(minLength): if int(versionParts[i]) < int(controlParts[i]): if self.logger: self.logger.customLog( "->[ERROR]: profile version is below the minimally supported version: {vers}.", translate=True, hideInConsole=False, vers=control) return False elif int(versionParts[i]) > int(controlParts[i]): if self.logger: self.logger.customLog( "->[CAUTION]: profile version is above this application's version.", translate=True, hideInConsole=False) return True def validateFilename(self, filename: str) -> bool: """ Validate that a filename doesn't contain banned characters. Args: filename (str): Filename to validate. Returns: bool -> True if filename contains no banned characters, False otherwise. Note: Banned characters are Windows filename restrictions: <>:"/\\|?* """ bannedChars = set('<>:"/\\|?*') if any((c in bannedChars) for c in filename): return False else: return True