I have a class that I use to have a single logger across my project.
import os
from logging import DEBUG, FileHandler, Formatter, Logger, StreamHandler, getLogger
from typing import Set
class SingleLogger:
__logger: Logger = None # type: ignore
__handler: StreamHandler = None # type: ignore
__logging_files: Set[str] = set()
@classmethod
def __create_and_configure_logger(cls) -> None:
if cls.__logger is not None:
return
logger = getLogger("shared_logger")
logger.level = DEBUG
stream_handler = StreamHandler()
stream_handler.level = DEBUG
stream_handler.formatter = Formatter(
"%(asctime)s %(name)s %(levelname)s: %(message)s"
)
__handler = stream_handler
logger.addHandler(__handler)
cls.__logger = logger
@classmethod
def add_filehandler_to_shared_logger(
cls, file: str = "/tmp/gipcheslogs.txt", for_notebook: bool = False
) -> None:
if file in cls.__logging_files:
return
try:
if not os.path.exists(file):
with open(file=file, mode="w", encoding="utf-8") as log_file:
log_file.write("")
log_file.close()
except IOError:
return
cls.__logging_files.add(file)
file_handler = FileHandler(file)
file_handler.level = DEBUG
file_handler.formatter = Formatter(
"%(asctime)s %(name)s %(levelname)s: %(message)s"
)
cls.shared_logger.addHandler(file_handler)
if for_notebook:
cls.__logger.removeHandler(cls.__handler)
@classmethod
@property
def shared_logger(cls) -> Logger:
"""
Returns:
Logger: the shared singleton logger, and create it if necessary.
"""
if not cls.__logger:
cls.__create_and_configure_logger()
return cls.__logger
SingleLogger.shared_logger.info(msg="Hello")
SingleLogger.shared_logger.debug(msg="Hello")
The code above runs with no problems on Python3.9 or above, but when I run the same code on Python3.8 or lower, I immediately get the following error:
AttributeError: 'property' object has no attribute 'info'
I’m not sure what is the difference between the two version of Python and why that affects the Logger.
Removing the @property from the shared_logger method and calling it using SingleLogger.shared_logger().info("Hi") fixes the issue, but once again, I don’t know why.
>Solution :
You’re wrapping a property with @classmethod. That was functionality added in 3.9… and removed in 3.11, because it turned out to be a bad idea that broke too much stuff.
Since it was added in 3.9, it will of course not work if you run your code on 3.8. Since it was removed in 3.11, you should stop using that functionality anyway.