# #region TestLoggingAuditFixes [C:3] [TYPE Module] [SEMANTICS test,logging,except,audit] # @BRIEF Verify Class 2 fix — no bare `except: pass` patterns remain in src/. # @RELATION BINDS_TO -> [EXT:frontend:PluginLoaderCore] # @TEST_EDGE: except_pass_replaced -> bare `except: pass` patterns are absent from src/ # @TEST_EDGE: plugin_loader_uses_logger -> plugin_loader.py uses logger, not print import ast import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent / "src")) class TestLoggingAuditFixes: """Verify that all bare `except: pass` patterns have been replaced with proper logging.""" PLUGIN_LOADER_PATH = Path(__file__).parent.parent / "src" / "core" / "plugin_loader.py" # #region _collect_src_files [C:1] [TYPE Function] # @BRIEF Collect all .py files under src/ excluding test/ and mock/ directories. @staticmethod def _collect_src_files(): src_root = Path(__file__).parent.parent / "src" return sorted( p for p in src_root.rglob("*.py") if "test" not in p.parts and "mock" not in p.parts and p.name != "__init__.py" ) # #endregion _collect_src_files # #region test_except_pass_replaced_with_log [C:2] [TYPE Function] # @BRIEF AST audit: bare `except: pass` nodes are absent from src/ source files. def test_except_pass_replaced_with_log(self): files_with_bare_except_pass = [] for filepath in self._collect_src_files(): try: tree = ast.parse(filepath.read_text(encoding="utf-8"), filename=str(filepath)) except SyntaxError: continue for node in ast.walk(tree): if not isinstance(node, ast.ExceptHandler): continue if node.type is not None: continue if len(node.body) == 1 and isinstance(node.body[0], ast.Pass): files_with_bare_except_pass.append(str(filepath)) break assert not files_with_bare_except_pass, ( f"Bare `except: pass` found in {len(files_with_bare_except_pass)} file(s):\n" + "\n".join(files_with_bare_except_pass) ) # #endregion test_except_pass_replaced_with_log # #region test_plugin_loader_uses_logger_not_print [C:2] [TYPE Function] # @BRIEF plugin_loader.py (src/core/) uses logger for error/warning, not print(). def test_plugin_loader_uses_logger_not_print(self): code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8") tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH)) # Find all print() calls in executable code print_lines = [] for node in ast.walk(tree): if (isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == "print"): print_lines.append(node.lineno) assert len(print_lines) == 0, ( f"plugin_loader.py still contains print() calls at lines: {print_lines}" ) # #endregion test_plugin_loader_uses_logger_not_print # #region test_plugin_loader_imports_logger [C:2] [TYPE Function] # @BRIEF plugin_loader.py imports a logger or _logger for structured reporting. def test_plugin_loader_imports_logger(self): code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8") tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH)) has_logger_import = False for node in ast.walk(tree): if isinstance(node, (ast.Import, ast.ImportFrom)): for alias in node.names: if "logger" in alias.name.lower(): has_logger_import = True break assert has_logger_import, ( "plugin_loader.py should import 'logger' or '_logger' " "for log-based error handling (instead of print)" ) # #endregion test_plugin_loader_imports_logger # #region test_plugin_loader_logger_calls_exist [C:2] [TYPE Function] # @BRIEF plugin_loader.py references logger.error/warning/info in its code. def test_plugin_loader_logger_calls_exist(self): code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8") tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH)) logger_calls = [] for node in ast.walk(tree): if (isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and isinstance(node.func.value, ast.Name) and "logger" in node.func.value.id.lower()): logger_calls.append((node.lineno, node.func.attr)) error_levels = {"error", "warning", "info", "debug", "reason", "reflect", "explore"} matching = [call for call in logger_calls if call[1] in error_levels] assert len(matching) >= 4, ( f"plugin_loader.py has only {len(matching)} logger.error/warning/info calls " f"(expected at least 4 for the 4 replaced print() statements): {matching}" ) # #endregion test_plugin_loader_logger_calls_exist # #endregion TestLoggingAuditFixes