From aa55adcdfb5c08f461d906737e103ab15d4c2859 Mon Sep 17 00:00:00 2001 From: Ayush Tripathi Date: Tue, 24 Mar 2026 19:42:12 +0530 Subject: [PATCH 1/3] Fix incorrect exception handling in FileClass and improve file I/O reliability with atomic writes and validation --- API/Classes/Base/FileClass.py | 103 +++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/API/Classes/Base/FileClass.py b/API/Classes/Base/FileClass.py index a4f07c8c4..7e207ffdc 100644 --- a/API/Classes/Base/FileClass.py +++ b/API/Classes/Base/FileClass.py @@ -1,49 +1,76 @@ #import ujson as json import json +import logging +from pathlib import Path +from typing import Any, Dict + +logger = logging.getLogger(__name__) + class File: + """ + Utility class for safe and consistent file I/O operations. + Provides JSON read/write helpers with proper error propagation + and optional logging for debugging. + """ + @staticmethod - def readFile(path): - try: - with open(path, mode="r") as f: - data = json.loads(f.read()) - return data - except IndexError: - raise IndexError - except IOError: - raise IOError - except OSError: - raise OSError + def _validate_path(path: str) -> Path: + """Validate and return a Path object. Ensures parent directory exists.""" + p = Path(path) + + if not p.parent.exists(): + raise FileNotFoundError(f"Directory does not exist: {p.parent}") + + return p @staticmethod - def writeFile(data, path): - try: - with open(path, mode="w") as f: - f.write(json.dumps(data, ensure_ascii=True, indent=4, sort_keys=False)) - except (IOError, IndexError): - raise IndexError - except OSError: - raise OSError + def readFile(path: str) -> Dict[str, Any]: + """ + Read JSON file and return parsed data. + Raises standard exceptions (FileNotFoundError, PermissionError, JSONDecodeError). + """ + p = File._validate_path(path) + + logger.debug(f"Reading file from: {p}") + + with p.open(mode="r", encoding="utf-8") as f: + return json.load(f) @staticmethod - def writeFileUJson(data, path): - try: - with open(path, mode="w") as f: - f.write(json.dumps(data)) - except (IOError, IndexError): - raise IndexError - except OSError: - raise OSError + def writeFile(data: Dict[str, Any], path: str) -> None: + """ + Write data to file in formatted JSON using atomic write. + """ + p = File._validate_path(path) + temp_path = p.with_suffix(p.suffix + ".tmp") + + logger.debug(f"Writing formatted JSON to: {p} (atomic)") + + with temp_path.open(mode="w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=True, indent=4, sort_keys=False) + + temp_path.replace(p) + + @staticmethod + def writeFileUJson(data: Dict[str, Any], path: str) -> None: + """ + Write data to file in compact JSON format using atomic write. + """ + p = File._validate_path(path) + temp_path = p.with_suffix(p.suffix + ".tmp") + + logger.debug(f"Writing compact JSON to: {p} (atomic)") + + with temp_path.open(mode="w", encoding="utf-8") as f: + json.dump(data, f, separators=(",", ":")) + + temp_path.replace(p) @staticmethod - def readParamFile(path): - try: - with open(path, mode="r") as f: - data = json.loads(f.read()) - return data - except IndexError: - raise IndexError - except IOError: - raise IOError - except OSError: - raise OSError \ No newline at end of file + def readParamFile(path: str) -> Dict[str, Any]: + """ + Read parameter JSON file. + Alias for readFile for semantic clarity. + """ + return File.readFile(path) \ No newline at end of file From 113d9699b66c68fc98cea3013bbffca9f7b4a56b Mon Sep 17 00:00:00 2001 From: Ayush Tripathi Date: Tue, 24 Mar 2026 20:06:51 +0530 Subject: [PATCH 2/3] Fix incorrect exception handling in FileClass and improve reliability with atomic writes --- API/Classes/Base/FileClass.py | 103 +++++++++++++--------------------- 1 file changed, 38 insertions(+), 65 deletions(-) diff --git a/API/Classes/Base/FileClass.py b/API/Classes/Base/FileClass.py index 7e207ffdc..a4f07c8c4 100644 --- a/API/Classes/Base/FileClass.py +++ b/API/Classes/Base/FileClass.py @@ -1,76 +1,49 @@ #import ujson as json import json -import logging -from pathlib import Path -from typing import Any, Dict - -logger = logging.getLogger(__name__) - class File: - """ - Utility class for safe and consistent file I/O operations. - Provides JSON read/write helpers with proper error propagation - and optional logging for debugging. - """ - @staticmethod - def _validate_path(path: str) -> Path: - """Validate and return a Path object. Ensures parent directory exists.""" - p = Path(path) - - if not p.parent.exists(): - raise FileNotFoundError(f"Directory does not exist: {p.parent}") - - return p + def readFile(path): + try: + with open(path, mode="r") as f: + data = json.loads(f.read()) + return data + except IndexError: + raise IndexError + except IOError: + raise IOError + except OSError: + raise OSError @staticmethod - def readFile(path: str) -> Dict[str, Any]: - """ - Read JSON file and return parsed data. - Raises standard exceptions (FileNotFoundError, PermissionError, JSONDecodeError). - """ - p = File._validate_path(path) - - logger.debug(f"Reading file from: {p}") - - with p.open(mode="r", encoding="utf-8") as f: - return json.load(f) + def writeFile(data, path): + try: + with open(path, mode="w") as f: + f.write(json.dumps(data, ensure_ascii=True, indent=4, sort_keys=False)) + except (IOError, IndexError): + raise IndexError + except OSError: + raise OSError @staticmethod - def writeFile(data: Dict[str, Any], path: str) -> None: - """ - Write data to file in formatted JSON using atomic write. - """ - p = File._validate_path(path) - temp_path = p.with_suffix(p.suffix + ".tmp") - - logger.debug(f"Writing formatted JSON to: {p} (atomic)") - - with temp_path.open(mode="w", encoding="utf-8") as f: - json.dump(data, f, ensure_ascii=True, indent=4, sort_keys=False) - - temp_path.replace(p) - - @staticmethod - def writeFileUJson(data: Dict[str, Any], path: str) -> None: - """ - Write data to file in compact JSON format using atomic write. - """ - p = File._validate_path(path) - temp_path = p.with_suffix(p.suffix + ".tmp") - - logger.debug(f"Writing compact JSON to: {p} (atomic)") - - with temp_path.open(mode="w", encoding="utf-8") as f: - json.dump(data, f, separators=(",", ":")) - - temp_path.replace(p) + def writeFileUJson(data, path): + try: + with open(path, mode="w") as f: + f.write(json.dumps(data)) + except (IOError, IndexError): + raise IndexError + except OSError: + raise OSError @staticmethod - def readParamFile(path: str) -> Dict[str, Any]: - """ - Read parameter JSON file. - Alias for readFile for semantic clarity. - """ - return File.readFile(path) \ No newline at end of file + def readParamFile(path): + try: + with open(path, mode="r") as f: + data = json.loads(f.read()) + return data + except IndexError: + raise IndexError + except IOError: + raise IOError + except OSError: + raise OSError \ No newline at end of file From e5a0de2556fb9a5f7b7b4f6d2db8a2f9f673380b Mon Sep 17 00:00:00 2001 From: Ayush Tripathi Date: Tue, 24 Mar 2026 20:09:31 +0530 Subject: [PATCH 3/3] Refactor FileClass with pathlib, logging, and atomic writes for robust file handling --- API/Classes/Base/FileClass.py | 103 +++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/API/Classes/Base/FileClass.py b/API/Classes/Base/FileClass.py index a4f07c8c4..a83f7a0ef 100644 --- a/API/Classes/Base/FileClass.py +++ b/API/Classes/Base/FileClass.py @@ -1,49 +1,76 @@ #import ujson as json import json +import logging +from pathlib import Path +from typing import Any, Dict + +logger = logging.getLogger(__name__) + class File: + """ + Utility class for safe and consistent file I/O operations. + Provides JSON read/write helpers with proper error propagation + and improved reliability. + """ + @staticmethod - def readFile(path): - try: - with open(path, mode="r") as f: - data = json.loads(f.read()) - return data - except IndexError: - raise IndexError - except IOError: - raise IOError - except OSError: - raise OSError + def _validate_path(path: str) -> Path: + """Validate and return a Path object. Ensures parent directory exists.""" + p = Path(path) + + if not p.parent.exists(): + raise FileNotFoundError(f"Directory does not exist: {p.parent}") + + return p @staticmethod - def writeFile(data, path): - try: - with open(path, mode="w") as f: - f.write(json.dumps(data, ensure_ascii=True, indent=4, sort_keys=False)) - except (IOError, IndexError): - raise IndexError - except OSError: - raise OSError + def readFile(path: str) -> Dict[str, Any]: + """ + Read JSON file and return parsed data. + Raises standard exceptions (FileNotFoundError, PermissionError, JSONDecodeError). + """ + p = File._validate_path(path) + + logger.debug(f"Reading file from: {p}") + + with p.open(mode="r", encoding="utf-8") as f: + return json.load(f) @staticmethod - def writeFileUJson(data, path): - try: - with open(path, mode="w") as f: - f.write(json.dumps(data)) - except (IOError, IndexError): - raise IndexError - except OSError: - raise OSError + def writeFile(data: Dict[str, Any], path: str) -> None: + """ + Write data to file in formatted JSON using atomic write. + """ + p = File._validate_path(path) + temp_path = p.with_suffix(p.suffix + ".tmp") + + logger.debug(f"Writing formatted JSON to: {p} (atomic)") + + with temp_path.open(mode="w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=True, indent=4, sort_keys=False) + + temp_path.replace(p) + + @staticmethod + def writeFileUJson(data: Dict[str, Any], path: str) -> None: + """ + Write data to file in compact JSON format using atomic write. + """ + p = File._validate_path(path) + temp_path = p.with_suffix(p.suffix + ".tmp") + + logger.debug(f"Writing compact JSON to: {p} (atomic)") + + with temp_path.open(mode="w", encoding="utf-8") as f: + json.dump(data, f, separators=(",", ":")) + + temp_path.replace(p) @staticmethod - def readParamFile(path): - try: - with open(path, mode="r") as f: - data = json.loads(f.read()) - return data - except IndexError: - raise IndexError - except IOError: - raise IOError - except OSError: - raise OSError \ No newline at end of file + def readParamFile(path: str) -> Dict[str, Any]: + """ + Read parameter JSON file. + Alias for readFile for semantic clarity. + """ + return File.readFile(path) \ No newline at end of file