import logging from queue import Queue, Empty from pyucc.utils import logger as ulogger class FakeTextWidget: def __init__(self): self._lines = [] self._tags = {} self._state = 'normal' self._yview = (0.0, 1.0) def winfo_exists(self): return True def tag_config(self, level_name, **kwargs): self._tags[level_name] = kwargs def configure(self, **kwargs): # noop or record state if 'state' in kwargs: self._state = kwargs['state'] def insert(self, pos, msg, tags=()): self._lines.append((pos, msg, tags)) def index(self, what): # return line count return f"{len(self._lines)+1}.0" def delete(self, a, b): self._lines = [] def see(self, what): pass def yview(self): return self._yview def get_all_text(self): return "\n".join([m for _, m, _ in self._lines]) def test_queue_putting_handler_puts_record(): q = Queue() h = ulogger.QueuePuttingHandler(q) rec = logging.LogRecord(name='test', level=logging.INFO, pathname=__file__, lineno=1, msg='hi', args=(), exc_info=None) h.emit(rec) got = q.get_nowait() assert isinstance(got, logging.LogRecord) assert got.msg == 'hi' def test_tkinter_text_handler_emit_and_flush_pending(monkeypatch): fake = FakeTextWidget() handler = ulogger.TkinterTextHandler(fake, {logging.INFO: 'black'}, max_lines=10) fmt = logging.Formatter('%(message)s') handler.setFormatter(fmt) # create record rec = logging.LogRecord(name='test', level=logging.INFO, pathname=__file__, lineno=10, msg='hello', args=(), exc_info=None) handler.emit(rec) # pending buffer should have one assert len(handler._pending_records) == 1 # flush pending should insert into fake widget handler.flush_pending() text = fake.get_all_text() assert 'hello' in text def test_process_global_log_queue_dispatch(monkeypatch): # prepare global queue with one record q = Queue() rec = logging.LogRecord(name='proc', level=logging.INFO, pathname=__file__, lineno=1, msg='msg1', args=(), exc_info=None) q.put(rec) monkeypatch.setattr(ulogger, '_global_log_queue', q) # fake console and file handlers class DummyHandler: def __init__(self): self.handled = [] def handle(self, record): self.handled.append(record) console = DummyHandler() fileh = DummyHandler() monkeypatch.setattr(ulogger, '_actual_console_handler', console) monkeypatch.setattr(ulogger, '_actual_file_handler', fileh) # fake tkinter handler fake = FakeTextWidget() tkhandler = ulogger.TkinterTextHandler(fake, {logging.INFO: 'black'}) fmt = logging.Formatter('%(message)s') tkhandler.setFormatter(fmt) monkeypatch.setattr(ulogger, '_actual_tkinter_handler', tkhandler) # fake root with after class FakeRoot: def after(self, ms, func): return 'after-id' def winfo_exists(self): return True monkeypatch.setattr(ulogger, '_tk_root_instance_for_processing', FakeRoot()) monkeypatch.setattr(ulogger, '_logging_system_active', True) # call processor ulogger._process_global_log_queue() # console and file handlers should have handled the record assert len(console.handled) == 1 assert len(fileh.handled) == 1 # tkinter handler flush_pending should have cleared pending assert len(tkhandler._pending_records) == 0 # cleanup monkeypatch.setattr(ulogger, '_logging_system_active', False) monkeypatch.setattr(ulogger, '_actual_console_handler', None) monkeypatch.setattr(ulogger, '_actual_file_handler', None) monkeypatch.setattr(ulogger, '_actual_tkinter_handler', None) monkeypatch.setattr(ulogger, '_global_log_queue', None) monkeypatch.setattr(ulogger, '_tk_root_instance_for_processing', None)