Skip to content

Commit 87978a9

Browse files
2byrdsByrdrlundeen2Copilot
authored
fix: handle closed logging streams in dispose_engine shutdown (#1526)
Co-authored-by: Byrd <lbyrd@CE-MAC-G453Q12CY4.corp.clearedgeit.com> Co-authored-by: Richard Lundeen <rlundeen@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent be00afa commit 87978a9

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

pyrit/memory/azure_sql_memory.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,15 @@ def dispose_engine(self) -> None:
640640
"""
641641
if self.engine:
642642
self.engine.dispose()
643-
logger.info("Engine disposed successfully.")
643+
# During interpreter shutdown, logging handler streams may already be closed,
644+
# causing the framework to print "Logging error" to stderr (GH-1520).
645+
# Temporarily suppress logging errors for this teardown message.
646+
previous_raise = logging.raiseExceptions
647+
logging.raiseExceptions = False
648+
try:
649+
logger.info("Engine disposed successfully.")
650+
finally:
651+
logging.raiseExceptions = previous_raise
644652

645653
def get_all_embeddings(self) -> Sequence[EmbeddingDataEntry]:
646654
"""

pyrit/memory/sqlite_memory.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,15 @@ def dispose_engine(self) -> None:
364364
"""
365365
if self.engine:
366366
self.engine.dispose()
367-
logger.info("Engine disposed and all connections closed.")
367+
# During interpreter shutdown, logging handler streams may already be closed,
368+
# causing the framework to print "Logging error" to stderr (GH-1520).
369+
# Temporarily suppress logging errors for this teardown message.
370+
previous_raise = logging.raiseExceptions
371+
logging.raiseExceptions = False
372+
try:
373+
logger.info("Engine disposed and all connections closed.")
374+
finally:
375+
logging.raiseExceptions = previous_raise
368376

369377
def export_conversations(
370378
self,

tests/unit/memory/test_sqlite_memory.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT license.
33

4+
import io
5+
import logging
46
import os
57
import uuid
68
from collections.abc import Sequence
@@ -670,6 +672,28 @@ def test_get_conversation_stats_batches_multiple_conversations(sqlite_instance):
670672
assert result[conv_ids[2]].message_count == 3
671673

672674

675+
def test_dispose_engine_tolerates_closed_log_stream(sqlite_instance, capsys):
676+
"""Verify dispose_engine does not raise or emit 'Logging error' when streams are closed (GH-1520)."""
677+
pyrit_logger = logging.getLogger("pyrit")
678+
prev_level = pyrit_logger.level
679+
pyrit_logger.setLevel(logging.INFO)
680+
681+
stream = io.StringIO()
682+
handler = logging.StreamHandler(stream)
683+
root = logging.getLogger()
684+
root.addHandler(handler)
685+
686+
try:
687+
stream.close()
688+
sqlite_instance.dispose_engine()
689+
finally:
690+
root.removeHandler(handler)
691+
pyrit_logger.setLevel(prev_level)
692+
693+
captured = capsys.readouterr()
694+
assert "Logging error" not in captured.err
695+
696+
673697
def test_create_engine_uses_static_pool_for_in_memory(sqlite_instance):
674698
"""In-memory databases must use StaticPool so all threads share one database."""
675699
from sqlalchemy.pool import StaticPool

0 commit comments

Comments
 (0)