diff --git a/modules/core.py b/modules/core.py index 52b9a30..d2b2bbe 100644 --- a/modules/core.py +++ b/modules/core.py @@ -1498,42 +1498,27 @@ long_jokes = false def _cleanup_web_viewer(self) -> None: """Cleanup web viewer resources on exit. - + Called by atexit handler to ensure the web viewer process is terminated properly when the bot shuts down. """ try: if hasattr(self, 'web_viewer_integration') and self.web_viewer_integration: - # Web viewer has simpler cleanup self.web_viewer_integration.stop_viewer() - try: - self.logger.info("Web viewer cleanup completed") - except (AttributeError, TypeError): - print("Web viewer cleanup completed") - except (OSError, AttributeError, TypeError) as e: - try: - self.logger.error(f"Error during web viewer cleanup: {e}") - except (AttributeError, TypeError): - print(f"Error during web viewer cleanup: {e}") + except (OSError, AttributeError, TypeError, ValueError, IOError): + pass # Do not log; stream may be closed during atexit def _cleanup_mesh_graph(self) -> None: """Cleanup mesh graph resources on exit. - + Called by atexit handler to ensure graph state is persisted properly when the bot shuts down. """ try: if hasattr(self, 'mesh_graph') and self.mesh_graph: self.mesh_graph.shutdown() - try: - self.logger.info("Mesh graph cleanup completed") - except (AttributeError, TypeError): - print("Mesh graph cleanup completed") - except (OSError, AttributeError, TypeError) as e: - try: - self.logger.error(f"Error during mesh graph cleanup: {e}") - except (AttributeError, TypeError): - print(f"Error during mesh graph cleanup: {e}") + except (OSError, AttributeError, TypeError, ValueError, IOError): + pass # Do not log; stream may be closed during atexit async def send_startup_advert(self) -> None: """Send a startup advertisement if configured. diff --git a/modules/mesh_graph.py b/modules/mesh_graph.py index 3bdfa31..7d46bbe 100644 --- a/modules/mesh_graph.py +++ b/modules/mesh_graph.py @@ -1393,18 +1393,12 @@ class MeshGraph: def shutdown(self): """Shutdown graph, flushing all pending writes.""" - self.logger.info("Shutting down mesh graph, flushing pending writes...") - + # Do not log here: atexit may run after the logger's stream is closed. # Signal shutdown self._shutdown_event.set() - + # Flush pending updates try: self._flush_pending_updates_sync() - except Exception as e: - self.logger.warning(f"Error flushing graph updates on shutdown: {e}") - - # Log final statistics - if self.edges: - total_observations = sum(e['observation_count'] for e in self.edges.values()) - self.logger.info(f"Graph shutdown complete: {len(self.edges)} edges, {total_observations} total observations") + except Exception: + pass # Avoid logging; stream may be closed during atexit diff --git a/tests/conftest.py b/tests/conftest.py index 1db8626..163f9e9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ import pytest import sqlite3 import configparser from contextlib import closing +from pathlib import Path from unittest.mock import Mock, MagicMock, AsyncMock from datetime import datetime, timedelta from typing import Any, Optional @@ -236,7 +237,8 @@ def mock_bot(mock_logger, test_config, test_db): bot.logger = mock_logger bot.config = test_config bot.db_manager = test_db - bot.bot_root = '/tmp' # Dummy path for testing + bot.bot_root = Path("/tmp") # Path for CommandManager local_commands_dir + bot._local_root = None # Use bot_root / local / commands in CommandManager bot.prefix_hex_chars = 2 # For path/prefix logic (PR #77) bot.key_prefix = lambda pk: (pk or '')[: getattr(bot, 'prefix_hex_chars', 2)] # For path_command graph selection diff --git a/tests/test_command_manager.py b/tests/test_command_manager.py index 4915252..f17b1a5 100644 --- a/tests/test_command_manager.py +++ b/tests/test_command_manager.py @@ -18,6 +18,7 @@ def cm_bot(mock_logger): bot = Mock() bot.logger = mock_logger bot.bot_root = Path("/tmp") + bot._local_root = None # Use bot_root / local / commands in CommandManager bot.config = ConfigParser() bot.config.add_section("Bot") bot.config.set("Bot", "bot_name", "TestBot") diff --git a/tests/test_command_prefix.py b/tests/test_command_prefix.py index 3e161e9..a1a6463 100644 --- a/tests/test_command_prefix.py +++ b/tests/test_command_prefix.py @@ -5,6 +5,7 @@ Tests that all commands properly handle command prefixes when enabled """ import pytest +from pathlib import Path from unittest.mock import Mock, MagicMock, patch from configparser import ConfigParser @@ -49,6 +50,8 @@ def mock_bot(): bot.bot_tx_rate_limiter = Mock() bot.bot_tx_rate_limiter.wait_for_tx = Mock() bot.tx_delay_ms = 0 + bot.bot_root = Path("/tmp") + bot._local_root = None # CommandManager uses bot_root / local / commands return bot