Reputation: 358
I'm trying to make a class based on an instance of another class. For this I use the __new__
method:
import logging
class Logger:
def __new__(cls):
logger = logging.getLogger('main')
# make a queue in a thread to put log messages in a PyQt text browser console
return logger
def close(self):
pass
# close the thread
def main():
logger = Logger()
# more things
logger.close()
if __name__ == '__main__':
main()
I am getting an AttributeError:
AttributeError: 'Logger' object has no attribute 'close'
My idea was to make a class that wraps around the instance returned from logging.getLogger('main') and be able to call both its original methods (like setLevel) and add my own.
The use of the logging module is not vital for my question, but it is an example of me not knowing how to use subclassing in this case.
My questions are:
__new__
method?Upvotes: 1
Views: 370
Reputation: 1428
You should probably just subclass them:
from logging import Logger
def MyLogger(Logger):
def close(self):
pass
if __name__ == "__main__":
logger = MyLogger("some_name")
logger.close()
That said, I have no clue why you'd need to manually close a logger. They'll handle their own shutdown at object deletion, which also happens when exiting Python. And you can remove them from their own structure without issues if you want to remove them halfway for some reason.
In a comment, OP clarified that this is meant to work with PyQt5. Here's what I've been using for the past year.
Widget for display of logging:
# my_package.gui.logwidget.py
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QTextEdit
from PyQt5.QtCore import QSize
from my_package.logger import handler
class LogWidget(QTextEdit):
"""
Creates a simple textEdit widget that will automatically subscribe to the QLogger.
"""
# pylint: disable=R0903, R0201
def __init__(self, parent=None):
super().__init__(parent)
handler.recordReady.connect(self.append)
self.setReadOnly(True)
# For reasons mere mortals like me cannot imagine, to get a real Monospaced font,
# we need to set it on a font that doesn't exist.
font = QFont("MichaelMcDoesntExist")
font.setStyleHint(QFont.Monospace)
self.setFont(font)
def minimumSizeHint(self) -> QSize:
return QSize(800, 200)
Actual logger:
# my_package.logger.py
import logging
from PyQt5.QtCore import QObject, pyqtSignal
class QLogHandler(QObject, logging.Handler):
"""
QObject subclass of logging.Handler. Will emit the log messages so QObjects can listen to it to catch log
messages.
Signal:
recordReady:
Will emit a string that is the formatted log message.
"""
recordReady = pyqtSignal(str)
def emit(self, record):
self.recordReady.emit(self.format(record))
def __repr__(self):
return f"<{self.__class__.__name__} : {logging.getLevelName(self.level)}>"
handler = QLogHandler() # Global ref to connect to it's signals
Python's builtin logging
module already supports threadsafe logging objects, so all you need to get it to work is to have a single loghandler, and any number of logging display widgets.
Upvotes: 2