User default exception

I created custom exceptions that take parameters and format their own message from constants. They are also printed on stdout, so the user understands the problem.

For instance:

defs.py:
PATH_NOT_FOUND_ERROR = 'Cannot find path "{}"'

exceptions.py:
class PathNotFound(BaseCustomException):
    """Specified path was not found."""

    def __init__(self, path):
        msg = PATH_NOT_FOUND_ERROR.format(path)
        print(msg)
        super(PathNotFound, self).__init__(msg)

some_module.py
raise PathNotFound(some_invalid_path)

I also want to log exceptions as they are raised, the easiest way:

logger.debug('path {} not found'.format(some_invalid_path)
raise PathNotFound(some_invalid_path)

But doing it all over the code seems redundant, and especially this makes constants pointless, because if I decide to change the wording, I also need to change the wording of the registrar.

I'm trying to do something like move registrar exception class, but it makes me lose the relevant properties LogRecord, such as name, module, filename, linenoetc. This approach is also losingexc_info

?

+4
1

- ,

, . logging.makeRecord, LogRecord

class MyLogger(logging.Logger):
    """Custom Logger."""

    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):
        """Override default logger to allow overridding internal attributes."""
        if six.PY2:
            rv = logging.LogRecord(name, level, fn, lno, msg, args, exc_info, func)
        else:
            rv = logging.LogRecord(name, level, fn, lno, msg, args, exc_info, func, sinfo)

        if extra is not None:
            for key in extra:
                # if (key in ["message", "asctime"]) or (key in rv.__dict__):
                #     raise KeyError("Attempt to overwrite %r in LogRecord" % key)
                rv.__dict__[key] = extra[key]
        return rv



logging.setLoggerClass(MyLogger)
logger = logging.getLogger(__name__)

class BaseCustomException(Exception):
    """Specified path was not found."""

    def __init__(self, path):
    """Override message with defined const."""
    try:
        raise ZeroDivisionError
    except ZeroDivisionError:
        # Find the traceback frame that raised this exception
        exception_frame = sys.exc_info()[2].tb_frame.f_back.f_back

    exception_stack = traceback.extract_stack(exception_frame, limit=1)[0]
    filename, lineno, funcName, tb_msg = exception_stack

    extra = {'filename': os.path.basename(filename), 'lineno': lineno, 'funcName': funcName}
    logger.debug(msg, extra=extra)
    traceback.print_stack(exception_frame)
    super(BaseCustomException, self).__init__(msg)
+2

Source: https://habr.com/ru/post/1694588/


All Articles