Skip to main content

Python terminal colored logger

Project description

tclogger

Python terminal colored logger

Install

pip install tclogger --upgrade

Usage

Run example:

python example.py

See: example.py

import sys
import tclogger
import time

from datetime import timedelta
from zoneinfo import ZoneInfo

from tclogger import TCLogger, logger, TCLogstr, logstr, colored, decolored
from tclogger import Runtimer, OSEnver, shell_cmd
from tclogger import get_now_ts, get_now_str, get_now_ts_str
from tclogger import TIMEZONE, set_timezone, tcdatetime
from tclogger import ts_to_str, str_to_ts, dt_to_str, unify_ts_and_str
from tclogger import CaseInsensitiveDict, dict_to_str, dict_get, dict_set
from tclogger import FileLogger
from tclogger import TCLogbar, TCLogbarGroup
from tclogger import brk, brc, brp
from tclogger import int_bits, max_key_len, chars_len


def test_logger_verbose():
    logger.note("Hello ", end="")
    logger.warn("You should not see this message", verbose=False)
    logger.mesg("World")
    logger.verbose = False
    logger.warn("You should not see later messages")
    logger.verbose = True
    logger.set_indent(2)
    logger.success("You should see this message, with indent")


def test_run_timer_and_logger():
    with Runtimer():
        logger.note(tclogger.__file__)
        logger.mesg(get_now_ts())
        logger.success(get_now_str())
        logger.note(f"Now: {logstr.mesg(get_now_str())}, ({logstr.file(get_now_ts())})")


def test_now_and_timezone():
    # Asia/Shanghai
    logger.success(TIMEZONE)
    logger.success(get_now_str())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.success(dt)
    # Europe/London
    set_timezone("Europe/London")
    logger.note(get_now_str())
    dt = tcdatetime(year=2024, month=10, day=31)
    logger.note(dt)
    logger.note(tcdatetime.strptime("2024-10-31", "%Y-%m-%d"))
    logger.note(tcdatetime.now())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.note(dt)
    logger.note(dt.strftime("%Y-%m-%d %H:%M:%S"))
    # America/New_York
    set_timezone("America/New_York")
    logger.warn(get_now_str())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.warn(dt)
    logger.warn(dt.astimezone(ZoneInfo("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S"))
    # Asia/Shanghai
    set_timezone("Asia/Shanghai")
    logger.success(get_now_str())


def test_dt_to_str():
    dt1 = timedelta(seconds=12)
    logger.note(f"dt1: {logstr.success(dt_to_str(dt1))}")
    dt2 = timedelta(seconds=60 * 24 + 12)
    logger.note(f"dt2: {logstr.success(dt_to_str(dt2))}")
    dt3 = timedelta(seconds=3600 * 8 + 60 * 24 + 12)
    logger.note(f"dt3: {logstr.success(dt_to_str(dt3))}")
    dt4 = timedelta(seconds=3600 * 24 * 1 + 3600 * 8 + 60 * 24 + 12)
    logger.note(f"dt4: {logstr.success(dt_to_str(dt4))}")

    t_ts = 1700000000
    t_ts, t_str = unify_ts_and_str(t_ts)
    logger.mesg(f"t_ts: {logstr.success(t_ts)}, t_str: {logstr.success(t_str)}")
    t_str = "2021-08-31 08:53:20"
    t_ts, t_str = unify_ts_and_str(t_str)
    logger.mesg(f"t_ts: {logstr.success(t_ts)}, t_str: {logstr.success(t_str)}")


def test_color():
    s1 = colored("hello", color="green", bg_color="bg_red", fonts=["bold", "blink"])
    s2 = colored("world", color="red", bg_color="bg_blue", fonts=["bold", "underline"])
    s3 = colored(f"BEG {s1} __ {s2} END")
    logger.note(s3)
    logger.success(s3)
    s4 = decolored(logstr.success(s3))
    print(s4)


def test_case_insensitive_dict():
    d = CaseInsensitiveDict()
    d["Hello"] = "old world"
    print(d["hello"])
    print(d)
    d["hELLo"] = "New WORLD"
    print(d["HEllO"])
    print(d)


def test_dict_get_and_set():
    d = {
        "owner": {"name": "Alice", "mid": 12345},
        "tags": ["tag1", "tag2", "tag3"],
        "children": [
            {
                "owner": {"name": "Bob", "mid": 54321},
                "tags": ["tag4", "tag5", "tag6"],
            }
        ],
    }
    print(dict_get(d, "owner.name"))
    print(dict_get(d, ["children", 0, "owner", "mid"]))
    dict_set(d, "owner.name", "Alice2")
    print(d)
    dict_set(d, ["owner", "mid"], 56789)
    print(d)
    print(dict_get(d, "owner.none", default="NotExist"))
    dict_set(d, "owner.new", "NewValue")
    print(d)
    dict_set(d, ["children", 1, "owner", "name"], "Bob2")
    print(d)
    dict_set(d, ["tags", 3], "tagsX")
    print(d)


def test_dict_to_str():
    d = {
        "hello": "world",
        "now": get_now_str(),
        "list": [1, 2, 3, [4, 5], "6"],
        "nested": {"key1": "value1", "key2": "value2", "key_3": {"subkey": "subvalue"}},
    }
    s = dict_to_str(d, add_quotes=True, max_depth=1)
    logger.success(s)
    s = dict_to_str(d, add_quotes=False, is_colored=False, max_depth=0)
    print(s)


def test_file_logger():
    file_logger = FileLogger(Path(__file__).parent / "test.log")
    file_logger.log("This is an error message", "error")


def test_align_dict_list():
    data = {
        "_id": None,
        "view_avg": 15175,
        "view_maxn": [94092954, 86624275, 68368263, 57713196, 53493614],
        "view_percentile": [39, 152, 254, 539, 3032, 13602, 51956, 282149, 94092954],
        "coin_avg": 57,
        "coin_maxn": [3093375, 2021980, 1420923, 1354206, 1312931],
        "coin_percentile": [0, 0, 0, 1, 6, 24, 76, 682, 3093375],
        "danmaku_avg": 26,
        "danmaku_maxn": [762005, 365521, 349354, 335414, 334935],
        "danmaku_percentile": [0, 0, 0, 0, 2, 12, 57, 353, 762005],
        "percentiles": [0.2, 0.4, 0.5, 0.6, 0.8, 0.9, 0.95, 0.99, 1.0],
        "sub_lists": {
            "sub1": [1, 2, 4, 5, 6],
            "sub2": [21, 2, 35, 43, 89],
            "sub3": ["a", "abc", "gh", "jkl", "qerq"],
            "sub4": ["x", "ef", "i", "mkns", "adfa"],
        },
    }
    print(dict_to_str(data, align_list=True))


def test_list_of_dicts():
    dict_data = {
        "list_of_lists": [[1, 2, 3], ["a", "b", "c"]],
        "list_of_dicts": [{"key1": "dict1"}, {"key2": "dict2", "key3": "dict3"}],
        "empty_list": [],
        "empty_dict": {},
    }
    print(dict_to_str(dict_data, align_list=True))
    print()
    list_data = [{"key1": "val1"}, {"key2": "val2"}, {"key10": "val10"}]
    print(dict_to_str(list_data, align_list=True))


def test_logbar():
    epochs = 3
    total = 1000000
    logbar = TCLogbar(
        total=total, show_datetime=False, flush_interval=0.1, grid_mode="symbol"
    )
    for epoch in range(epochs):
        for i in range(total):
            logbar.update(increment=1)
            logbar.set_head(f"[{epoch+1}/{epochs}]")
        logbar.grid_mode = "shade"
        logbar.set_desc("THIS IS A SO LONG DESC WHICH IS USED TO TEST LINE UP")
        logbar.reset()


def test_logbar_group():
    epochs = 3
    total = 100
    sub_total = 1000
    epoch_bar = TCLogbar(total=epochs)
    epoch_bar.set_desc(f"[0/{epochs}]")
    progress_bar = TCLogbar(total=total)
    sub_progress_bar = TCLogbar(total=sub_total)
    TCLogbarGroup([epoch_bar, progress_bar, sub_progress_bar], show_at_init=True)
    # TCLogbarGroup([epoch_bar, progress_bar, sub_progress_bar], show_at_init=False)
    # print("This is a noise line to test lazy blank prints of logbar group.")
    # epoch_bar.update(0)
    for epoch in range(epochs):
        for i in range(total):
            for j in range(sub_total):
                sub_progress_bar.update(1, desc=f"[{j+1}/{sub_total}]")
                time.sleep(0.01)
            sub_progress_bar.reset()
            progress_bar.update(1, desc=f"[{i+1}/{total}]")
        progress_bar.reset()
        epoch_bar.set_desc()
        epoch_bar.update(1, desc=f"[{epoch+1}/{epochs}]", flush=True)


def test_logbar_total():
    total = 500

    logbar = TCLogbar()
    for i in range(total):
        logbar.update(1)
        time.sleep(0.001)
    logbar.flush()
    print()

    logbar = TCLogbar(total=total)
    for i in range(total + 250):
        logbar.update(1)
        time.sleep(0.01)


def test_logbar_verbose():
    total = 1000
    logbar1 = TCLogbar(total=total, show_datetime=False, head="bar1", verbose=False)
    logger.note("> Here should NOT show bar1")
    for i in range(total):
        logbar1.update(1)
    print()

    logbar2 = TCLogbar(total=total, show_datetime=False, head="bar2", verbose=True)
    logger.note("> Here should show bar2")
    for i in range(total):
        logbar2.update(1)
    print()

    logger.note("> Here should NOT show bar1 and bar2")
    TCLogbarGroup([logbar1, logbar2], verbose=False)
    print()

    logger.note("> Here should show bar1 and bar2")
    TCLogbarGroup([logbar1, logbar2], verbose=True)
    print()


def test_decorations():
    text = "Hello World"
    logger.note(f"Brackets: {logstr.mesg(brk(text))}")
    logger.note(f"Braces  : {logstr.mesg(brc(text))}")
    logger.note(f"Parens  : {logstr.mesg(brp(text))}")


def test_math():
    texts = ["你好", "Hello", 12345, "你好,世界!", "Hello, World!"]
    res = {}
    for text in texts:
        text_len = chars_len(text)
        res[text] = text_len
    key_max_len = max_key_len(res)
    for text, text_len in res.items():
        text_str = str(text) + " " * (key_max_len - chars_len(str(text)))
        text_len_str = logstr.mesg(brk(text_len))
        logger.note(f"{text_str} : {text_len_str}")


if __name__ == "__main__":
    test_logger_verbose()
    test_run_timer_and_logger()
    test_now_and_timezone()
    test_dt_to_str()
    test_color()
    test_case_insensitive_dict()
    test_dict_get_and_set()
    test_dict_to_str()
    test_align_dict_list()
    test_list_of_dicts()
    test_file_logger()
    test_logbar()
    test_logbar_group()
    test_logbar_total()
    test_logbar_verbose()
    test_decorations()
    test_math()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tclogger-1.2.5.tar.gz (19.1 kB view details)

Uploaded Source

Built Distribution

tclogger-1.2.5-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

Details for the file tclogger-1.2.5.tar.gz.

File metadata

  • Download URL: tclogger-1.2.5.tar.gz
  • Upload date:
  • Size: 19.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for tclogger-1.2.5.tar.gz
Algorithm Hash digest
SHA256 5cc270ed5ad601d3f9576cc58f7ab678f4128c46297c5718a940691785ecff7e
MD5 07ff8992af135f6da39b4ac1f9c0237a
BLAKE2b-256 3f7e6034a9bfe60fd2ff5585cae9a77ddfcb1c4280fcf0ca3fae36be7c898f2a

See more details on using hashes here.

File details

Details for the file tclogger-1.2.5-py3-none-any.whl.

File metadata

  • Download URL: tclogger-1.2.5-py3-none-any.whl
  • Upload date:
  • Size: 19.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for tclogger-1.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 792b949683df173bed35ba0af8584b7f3d6bf8670aaaf8456ada42fe728d6f38
MD5 b874897df2997eee140b4da417500d26
BLAKE2b-256 1a206a0fad7866f7ffb5ef75063df266333dff40091919cf661ff7e976c09c15

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page