Module pyboiler.internal.log.format

Wrap python.logging Formatters

Expand source code
"""Wrap python.logging Formatters"""

import re
from enum import Enum, auto
from typing import Any

from ...generic import slot_storage
from .config import config
from .record import Record

from ..color.colors import parse as c_parse
from ..color.colors import ST
from ..color.config import config as c_conf

from .level import LevelColors


class TagWrapper(slot_storage):
    __slots__ = ("tag", "inst", "val")

    def __init__(self, idx: int, tag: str, inst, val: Any = None):
        self.idx: int
        self.tag = tag
        self.inst = inst
        self.val = val

    def __str__(self) -> str:
        return f"{type(self).__name__} tag: {self.tag}, val: {self.val}"


class Tags(Enum):
    name = auto()
    levelnum = auto()
    levelname = auto()
    filepath = auto()
    filename = auto()
    linenum = auto()
    func = auto()
    time = auto()
    message = auto()

    @staticmethod
    def parse(string: str):
        raw_tags = re.findall(config.TAG_RE, string)
        tags = []
        for idx, item in enumerate(raw_tags):
            tag = item[2:-1]
            wrap = TagWrapper(idx, item, Tags[tag])
            tags.append(wrap)
        return tags


class TagsColor(Enum):
    name = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}bBLACK{c_conf.TAG_END}{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    levelnum = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}fWHITE{c_conf.TAG_END}"
    levelname = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}fWHITE{c_conf.TAG_END}"
    filepath = f"{c_conf.TAG_START}fBLUE{c_conf.TAG_END}"
    filename = f"{c_conf.TAG_START}fBLUE{c_conf.TAG_END}"
    linenum = f"{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    func = f"{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    time = f"{c_conf.TAG_START}fYELLOW{c_conf.TAG_END}"
    message = ""  # Defined in level.LevelColors


class Formatter:
    """Log record formatter"""

    __slots__ = ("fmt", "datefmt", "color")

    def __init__(self, fmt: str = None, datefmt: str = None, color=False):  # type: ignore
        if fmt is None:
            fmt = config.DFLT_FMT
        if datefmt is None:
            datefmt = config.DFLT_DATEFMT
        self.fmt = fmt
        self.datefmt = datefmt
        self.color = color

    @staticmethod
    def _parse(string):
        return Tags.parse(string)

    @staticmethod
    def _add_vals(tags, record: Record, datefmt, color: bool):
        mapping = {
            Tags.name: record.name,
            Tags.levelnum: record.level.value,
            Tags.levelname: record.level.name,
            Tags.filepath: str(record.meta.filepath),
            Tags.filename: record.meta.filepath.name,
            Tags.linenum: record.meta.line,
            Tags.func: record.meta.func,
            Tags.time: record.time.strftime(datefmt),
            Tags.message: record.msg,
        }
        if not color:
            for tag in tags:
                tag.val = mapping[tag.inst]
        else:
            for tag in tags:
                col = TagsColor[tag.inst.name].value
                if tag.inst.name == "message":
                    col = LevelColors[record.level.name].value
                tag.val = ""
                if col:
                    col_fmt = c_parse(col)
                    for fmt in col_fmt:
                        tag.val += fmt.val
                    tag.val += f"{mapping[tag.inst]}{ST.RESET.code()}"
                else:
                    tag.val = mapping[tag.inst]

    def format(self, record: Record) -> str:
        tags = type(self)._parse(self.fmt)
        type(self)._add_vals(tags, record, self.datefmt, self.color)

        message = self.fmt
        for tag in tags:
            message = message.replace(tag.tag, tag.val)
        return message


default = Formatter()
colored = Formatter(color=True)

Classes

class Formatter (fmt: str = None, datefmt: str = None, color=False)

Log record formatter

Expand source code
class Formatter:
    """Log record formatter"""

    __slots__ = ("fmt", "datefmt", "color")

    def __init__(self, fmt: str = None, datefmt: str = None, color=False):  # type: ignore
        if fmt is None:
            fmt = config.DFLT_FMT
        if datefmt is None:
            datefmt = config.DFLT_DATEFMT
        self.fmt = fmt
        self.datefmt = datefmt
        self.color = color

    @staticmethod
    def _parse(string):
        return Tags.parse(string)

    @staticmethod
    def _add_vals(tags, record: Record, datefmt, color: bool):
        mapping = {
            Tags.name: record.name,
            Tags.levelnum: record.level.value,
            Tags.levelname: record.level.name,
            Tags.filepath: str(record.meta.filepath),
            Tags.filename: record.meta.filepath.name,
            Tags.linenum: record.meta.line,
            Tags.func: record.meta.func,
            Tags.time: record.time.strftime(datefmt),
            Tags.message: record.msg,
        }
        if not color:
            for tag in tags:
                tag.val = mapping[tag.inst]
        else:
            for tag in tags:
                col = TagsColor[tag.inst.name].value
                if tag.inst.name == "message":
                    col = LevelColors[record.level.name].value
                tag.val = ""
                if col:
                    col_fmt = c_parse(col)
                    for fmt in col_fmt:
                        tag.val += fmt.val
                    tag.val += f"{mapping[tag.inst]}{ST.RESET.code()}"
                else:
                    tag.val = mapping[tag.inst]

    def format(self, record: Record) -> str:
        tags = type(self)._parse(self.fmt)
        type(self)._add_vals(tags, record, self.datefmt, self.color)

        message = self.fmt
        for tag in tags:
            message = message.replace(tag.tag, tag.val)
        return message

Instance variables

var color

Return an attribute of instance, which is of type owner.

var datefmt

Return an attribute of instance, which is of type owner.

var fmt

Return an attribute of instance, which is of type owner.

Methods

def format(self, record: Record) ‑> str
Expand source code
def format(self, record: Record) -> str:
    tags = type(self)._parse(self.fmt)
    type(self)._add_vals(tags, record, self.datefmt, self.color)

    message = self.fmt
    for tag in tags:
        message = message.replace(tag.tag, tag.val)
    return message
class TagWrapper (idx: int, tag: str, inst, val: Any = None)

Children of this class must have slots defined

Expand source code
class TagWrapper(slot_storage):
    __slots__ = ("tag", "inst", "val")

    def __init__(self, idx: int, tag: str, inst, val: Any = None):
        self.idx: int
        self.tag = tag
        self.inst = inst
        self.val = val

    def __str__(self) -> str:
        return f"{type(self).__name__} tag: {self.tag}, val: {self.val}"

Ancestors

Instance variables

var inst

Return an attribute of instance, which is of type owner.

var tag

Return an attribute of instance, which is of type owner.

var val

Return an attribute of instance, which is of type owner.

Inherited members

class Tags (*args, **kwds)

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access:

Color.RED

  • value lookup:

Color(1)

  • name lookup:

Color['RED']

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.

Expand source code
class Tags(Enum):
    name = auto()
    levelnum = auto()
    levelname = auto()
    filepath = auto()
    filename = auto()
    linenum = auto()
    func = auto()
    time = auto()
    message = auto()

    @staticmethod
    def parse(string: str):
        raw_tags = re.findall(config.TAG_RE, string)
        tags = []
        for idx, item in enumerate(raw_tags):
            tag = item[2:-1]
            wrap = TagWrapper(idx, item, Tags[tag])
            tags.append(wrap)
        return tags

Ancestors

  • enum.Enum

Class variables

var filename
var filepath
var func
var levelname
var levelnum
var linenum
var message
var name
var time

Static methods

def parse(string: str)
Expand source code
@staticmethod
def parse(string: str):
    raw_tags = re.findall(config.TAG_RE, string)
    tags = []
    for idx, item in enumerate(raw_tags):
        tag = item[2:-1]
        wrap = TagWrapper(idx, item, Tags[tag])
        tags.append(wrap)
    return tags
class TagsColor (*args, **kwds)

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access:

Color.RED

  • value lookup:

Color(1)

  • name lookup:

Color['RED']

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.

Expand source code
class TagsColor(Enum):
    name = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}bBLACK{c_conf.TAG_END}{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    levelnum = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}fWHITE{c_conf.TAG_END}"
    levelname = f"{c_conf.TAG_START}sBOLD{c_conf.TAG_END}{c_conf.TAG_START}fWHITE{c_conf.TAG_END}"
    filepath = f"{c_conf.TAG_START}fBLUE{c_conf.TAG_END}"
    filename = f"{c_conf.TAG_START}fBLUE{c_conf.TAG_END}"
    linenum = f"{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    func = f"{c_conf.TAG_START}fGREEN{c_conf.TAG_END}"
    time = f"{c_conf.TAG_START}fYELLOW{c_conf.TAG_END}"
    message = ""  # Defined in level.LevelColors

Ancestors

  • enum.Enum

Class variables

var filename
var filepath
var func
var levelname
var levelnum
var linenum
var message
var name
var time