From ea9913846987c556d025d077d34d8f7eb43180f2 Mon Sep 17 00:00:00 2001 From: theonepath Date: Tue, 3 May 2022 18:16:54 +0100 Subject: [PATCH] Updated utils/printfmt.py Module given docstrings to explain the purpose and function of defined module functions. Giving parameter and return values of functions. Module now contains `gen_log_header` moved from the `Logger` class, along with global constants for the function. --- utils/printfmt.py | 75 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/utils/printfmt.py b/utils/printfmt.py index d4afb37..1750488 100644 --- a/utils/printfmt.py +++ b/utils/printfmt.py @@ -1,7 +1,16 @@ import textwrap +import time from typing import Union + from .common import LogLevel + +## log message constant format template +__LOG_TMPL = "[{DATE}] [{0}] {TYPE} " +## string time format (ISO: 8601, long-form) +__TIMESTAMP_FMT = "%Y-%m-%dT%H:%M:%S%z" + + class Colours: NORMAL = '\033[0m' RED = '\033[91m' @@ -11,6 +20,12 @@ class Colours: def loglevel_as_str(level: Union[LogLevel, int]) -> str: + """Convert an integer or enum value into its appropriate enum + attribute name. + + `@Params`: level - `LogLevel | int` + `Returns`: LogLevel enum literal attribute name - `str` + """ ## perform a lookup of each attribute of LogLevel and its associate ## value, and search for the attribute that has the matching level ## value passed to the function. @@ -20,10 +35,18 @@ def loglevel_as_str(level: Union[LogLevel, int]) -> str: if getattr(LogLevel, _) == level: # if the level matches return "{0: <5}".format(_) # return the attribute name - return " " + return " " * 5 -def logAsCol(level: Union[int, LogLevel]) -> Colours: +def log_as_col(level: Union[int, LogLevel]) -> Colours: + """Convert an integer or enum value into an associated ANSI escape + code terminal colour sequence. Depending on log level severity, an + associated colour is returned to give STDOUT text a distinct + separation of colour from regular STDOUT text. + + `@Params`: level - `LogLevel | int` + `@Return`: Enum of `Colours` + """ ## perform a colour lookup based on level number if level == LogLevel.DEBUG: return Colours.BLUE @@ -36,6 +59,54 @@ def logAsCol(level: Union[int, LogLevel]) -> Colours: else: return Colours.NORMAL +def gen_log_header(_type: Union[LogLevel, int, str]) -> str: + """Generate a header string for use of standardising log outputs. + + The header is defined using the following standard header: + ```plaintext + "[YYYY-MM-DDTHH:MM:SS+OFFSET] [{CALLER}] {0}" + ``` + + The first column defines the Date-Time following the ISO 8601 (long) + standard timestamp format, whereby `T` is the separator between Date + and Time. The `+OFFSET` is the number of hours ahead/behind UTC, the + currently timezone set by the PC. This is achieved using the following + string to time format: + `%Y-%m-%dT%H:%M:%S%z`. + + The second column is reversed during the return value of the string. + This column is used to allow for a stacktrace to be attached to the + log message. + + The third column defines the level of the log message. This will be + five blank space characters if a level is passed outside of the + defined scope of logging levels. + + The fourth column is reserved during the return value of the string. + It represents the body of the message to be logged. + + + `@Params`: _type - `LogLevel | int | str` + `@Return`: Formattable string - `str` + """ + ## if the _type represents a LogLevel value, convert it to str + if not isinstance(_type, str): + _type = loglevel_as_str(_type) + + ## return newly formatted log message header + return __LOG_TMPL.format('{CALLER}', DATE=\ + time.strftime(__TIMESTAMP_FMT, time.localtime()), + TYPE=_type) + "{0}" + def wrap(value: str, *, width: int = 120, tb_size: int = 4) -> str: + """Return a hard-wrapped string defined by a fixed width. + + Wrapped text is separated by a `\\n` character and a fixed width of + 120 characters. Each wrap is appended with a tab size of 4 characters + at the start of each line-wrap. + + `@Params`: value - `str`, width = 120 - `int`, tb_size = 4 - `int` + `@Return`: `str` + """ return "\n".join(textwrap.wrap(value, width=width, tabsize=tb_size)) \ No newline at end of file